Skip to main content

Web Elements Services

Basis Theory Web Elements offers a set of services that enable you to securely collect, manage, and share sensitive data without exposing it to your application code. This document explains the available services and how to use them in your applications.

Overview

The services provided by Basis Theory Web Elements fall into four main categories:

  • Data Collection - Securely collect and tokenize sensitive data
  • Data Retrieval - Safely detokenize and reveal sensitive data
  • Session Management - Create and manage temporary access sessions
  • Third-Party Integration - Securely interact with third-party APIs
Each service is designed to maintain a security boundary for sensitive data. The actual input data never leaves the element (iframe) other than to hit our secure API endpoints.

Element Methods

Elements provide several methods for interacting with and manipulating their values securely. These methods allow you to programmatically control elements while maintaining the security boundary.

For detailed documentation on all available methods, see the Element Methods reference.

Data Collection

Tokenizing Data

Basis Theory Elements can securely tokenize sensitive data without exposing it to your application. You can tokenize data using two primary approaches:

1. Create a Single Token

The tokens.create method creates a single token with your sensitive data:

// Create a token containing sensitive data
bt.tokens
.create({
type: "token", // Specify the token type
data: {
// Include element instances containing sensitive data
sensitiveData: sensitiveDataElement, // Data remains in secure iframe

// Include non-sensitive data directly
nonSensitiveData: "plainText",

// Nested data structures are supported
otherData: {
someInteger: 20,
someBoolean: false,
},
someOtherData: ["plainText1", "plainText2"],
},
// Optional metadata (non-sensitive)
metadata: {
nonSensitiveField: "nonSensitiveValue",
},
})
.then((token) => {
// Save the token ID for future reference
console.log(token.id);

// Full response includes masked/redacted data
console.log(JSON.stringify(token));
});
When submitting plainText values, data will be HTML encoded before storage for security reasons.

Create a Card Token

For payment card data, you can use either the combined CardElement or individual card elements:

// Option 1: Using the combined CardElement
bt.tokens
.create({
type: "card", // Specific type for cards
data: cardElement, // Pass the entire card element
})
.then((token) => {
console.log(token.id); // Token to store
console.log(JSON.stringify(token.data)); // Contains masked card data
});

// Option 2: Using individual card elements
bt.tokens
.create({
type: "card",
data: {
// Each piece of card data in a separate element
number: cardNumberElement,
expiration_month: cardExpirationDateElement.month(), // Using the data parsing method
expiration_year: cardExpirationDateElement.year(),
cvc: cardVerificationCodeElement
}
})
.then((token) => {
console.log(token.id);
console.log(JSON.stringify(token.data)); // Masked card data
});

Create a Bank Account Token

For bank account information:

bt.tokens
.create({
type: "bank",
data: {
routingNumber: routingNumberElement,
accountNumber: accountNumberElement,
},
})
.then((token) => {
console.log(token.id); // Token to store
console.log(JSON.stringify(token.data)); // Contains redacted bank data
});

2. Tokenize Multiple Values at Once

The tokenize method allows you to create multiple tokens in a single operation:

// Tokenize multiple pieces of data at once
bt.tokenize({
// Create two card tokens with different approaches
card1: {
type: "card",
data: cardElement, // Using the combined card element
},
card2: {
type: "card",
data: {
// Using individual card elements
number: cardNumberElement,
expiration_month: cardExpirationDateElement.month(),
expiration_year: cardExpirationDateElement.year(),
cvc: cardVerificationCodeElement,
},
},
// Create a generic token
sensitiveData: sensitiveDataElement,

// Include non-sensitive data
nonSensitiveData: "plainText",
otherData: {
someInteger: 20,
someBoolean: false,
},
someOtherData: ["plainText1", "plainText2"],
}).then((tokens) => {
// Multiple token IDs returned in the response
console.log(tokens.card1.id, tokens.card2.id, tokens.sensitiveData);

// Full response with all tokens
console.log(JSON.stringify(tokens));
});

Updating Tokens

You can update existing tokens with new values from Elements:

// Update an existing token with a new value
bt.tokens
.update("ca9f3fd7-3906-4087-83aa-9a6129221297", { // Token ID to update
data: cardElement, // New data from an element
})
.then((token) => {
// Response contains redacted/masked updated data
console.log(JSON.stringify(token.data));
});

Creating Token Intents

Token Intents provide a way to create tokens that require additional verification before being usable:

// Create a token intent for a card
bt.tokenIntents
.create({
type: "card",
data: cardElement // Pass the card element
})
.then((tokenIntent) => {
// Use this ID to validate and convert to a token
console.log(tokenIntent.id);
});

// Alternative: Create with individual elements
bt.tokenIntents
.create({
type: "card",
data: {
number: cardNumberElement,
expiration_month: cardExpirationDateElement.month(),
expiration_year: cardExpirationDateElement.year(),
cvc: cardVerificationCodeElement
}
})
.then((tokenIntent) => {
console.log(tokenIntent.id);
});

Data Retrieval

Retrieving and Displaying Tokenized Data

To securely retrieve and display tokenized data, use the tokens.retrieve method with the Element's setValue method:

// First, create an element to display the data
const textElement = bt.createElement("text", {
targetId: "text-element",
});

// Retrieve the token and set its value into the element
bt.tokens
.retrieve("ca9f3fd7-3906-4087-83aa-9a6129221297", {
apiKey: "<SESSION_API_KEY>", // Session key with appropriate permissions
})
.then((token) => {
// Set the tokenized data into the element
textElement.setValue(token.data);
});
The data attribute in the token returned by retrieve is not the actual data, but a synthetic representation. The real sensitive data remains secure within the Element.
Non-sensitive token attributes like metadata are directly accessible from the response.

Displaying Card Data

For card data, you can populate either a combined CardElement or individual card elements:

// Option 1: Display in a combined CardElement
const cardElement = bt.createElement("card");

bt.tokens
.retrieve("ca9f3fd7-3906-4087-83aa-9a6129221297", {
apiKey: "<SESSION_API_KEY>",
})
.then((token) => {
// Set the entire card data object
cardElement.setValue(token.data);
});

// Option 2: Display in individual elements
const cardNumberElement = bt.createElement("cardNumber", {
targetId: "card-number",
});
const cardExpirationDateElement = bt.createElement("cardExpirationDate", {
targetId: "card-expiration-date"
});

bt.tokens
.retrieve("ca9f3fd7-3906-4087-83aa-9a6129221297", {
apiKey: "<SESSION_API_KEY>",
})
.then((token) => {
// Set each piece into the appropriate element
cardNumberElement.setValue(token.data.number);
cardExpirationDateElement.setValue({
month: token.data.expiration_month,
year: token.data.expiration_year,
});
});

Session Management

Sessions provide a secure way to grant temporary elevated access to tokenized data on the frontend, enabling features like:

  • Displaying masked card data to users
  • Allowing users to update saved payment methods
  • Verifying identity with sensitive information

Learn more about sessions and access controls.

Creating Sessions

You can create a new session for a Public Application:

// Create a session for temporary elevated access
const session = await bt.sessions.create();
Sessions cannot be authorized directly from the frontend. All session authorization must be performed by a Private Application on your backend. This security measure prevents unauthorized access to sensitive data.

Third-Party Integration

Proxy Service

The Proxy Service allows you to securely forward Element data to third-party APIs without exposing the sensitive data to your application.

// Create elements for the request and response
const submitElement = bt.createElement("text", {
targetId: "submitElement", // Element containing data to send
});
const revealElement = bt.createElement("text", {
targetId: "revealElement", // Element to display the response
});

// Make a POST request through the proxy
bt.proxy
.post({
headers: {
"BT-PROXY-KEY": "e29a50980ca5", // Your pre-configured proxy key
},
body: {
sensitiveValue: submitElement, // Element containing sensitive data
nonSensitiveValue: "plainText", // Regular data
},
apiKey: "<SESSION_API_KEY>", // Session key with appropriate permissions
})
.then((response) => {
// Display the response data in the reveal element
revealElement.setValue(response.value);
});
The proxy response object is a synthetic representation of sensitive data, not the actual data. The real sensitive data remains secure within the Element.

Supported HTTP Methods

The Proxy Service supports all standard HTTP methods:

// GET request
bt.proxy.get(options);

// POST request
bt.proxy.post(options);

// PUT request
bt.proxy.put(options);

// PATCH request
bt.proxy.patch(options);

// DELETE request
bt.proxy.delete(options);

Proxy Request Options

OptionTypeRequiredDescription
pathstringNoString appended to the end of the proxied URL path
queryobjectNoKey/value pairs added as query parameters
headersobjectNoKey/value pairs added as HTTP headers
bodyobjectNoPayload sent to the proxied URL (can contain Elements)
apiKeystringNoBasisTheory API Key for authentication
correlationIdstringNoID for request correlation
idempotencyKeystringNoKey for request idempotency

Accessing Non-Sensitive Proxy Responses
Beta

Our Elements enable you to convert proxy responses into plain text, which is ideal for non-sensitive data handling. This enhancement streamlines your data processing workflows and facilitates an easier understanding of the returned data, bypassing decryption or tokenization.

This feature is currently invite-only. If you're interested, please get in touch for an invitation.

You can capture values from any of our Elements; hence we strongly recommend only using this feature for non-sensitive data. Converting proxy responses to plain text can expose the underlying data to risks, such as unauthorized access or leakage. Ensure the plain-text proxy responses align with your data security policy, data handling practices, and compliance obligations. If you're unsure, please get in touch for guidance at www.basistheory.com/contact

HTTP Client Service

The HTTP Client Service enables you to make requests to third-party APIs with Element data in the payload:

// Initialize BasisTheory
const bt = await basistheory("<API_KEY>");

// Make a POST request with sensitive data
bt.client.post(
"https://www.api.thirdpartydomain.com/resources",
{
sensitiveData: sensitiveDataElement, // Element containing sensitive data
nonSensitiveData: "plainText",
otherData: {
someInteger: 20,
someBoolean: false,
}
},
{
headers: {
"Content-Type": "application/json"
}
}
).then((response) => {
// Full plaintext response is accessible
console.log(JSON.stringify(response));
});
The response from this service is the actual plaintext data. It may contain sensitive data depending on the third-party API response.

Supported HTTP Methods

The HTTP Client Service supports all standard HTTP methods:

// GET request
bt.client.get(url, options);

// POST request
bt.client.post(url, body, options);

// PUT request
bt.client.put(url, body, options);

// PATCH request
bt.client.patch(url, body, options);

// DELETE request
bt.client.delete(url, options);

Error Handling

Basis Theory Service Errors

When using Basis Theory services, you may encounter two main types of errors:

import { BasisTheoryApiError, BasisTheoryValidationError } from "@basis-theory/web-elements/common";

bt.tokenize({
card1: {
type: "card",
data: cardElement1,
},
card2: {
type: "card",
data: cardElement2,
},
ssn: textElement,
}).catch((error) => {
if (error instanceof BasisTheoryValidationError) {
// Client-side validation failure
// Example: incomplete or invalid element data
console.error("Validation error:", error.details);

// Check specific field errors
if (error.details.card1?.number?.type === 'invalid') {
// Handle invalid card number
}
} else if (error instanceof BasisTheoryApiError) {
// Server-side error
console.error(`API error ${error.status}:`, error.data);
}
});

HTTP Client Service Errors

HTTP client services can throw similar validation errors, plus HTTP-specific errors:

import { HttpClientError, BasisTheoryValidationError } from "@basis-theory/web-elements/common";

const bt = await basistheory("<API_KEY>");

bt.client.post(
"https://api.example.com/data",
{
sensitiveData: textElement,
}
).catch((error) => {
if (error instanceof BasisTheoryValidationError) {
// Client-side validation failure
console.error("Validation error:", error.details);
} else if (error instanceof HttpClientError) {
// HTTP error from the third-party API
console.error(`HTTP error ${error.status}:`, error.data);
console.log("Response headers:", error.headers);
}
});

Error Types Reference

BasisTheoryValidationError

{
name: "BasisTheoryValidationError",
details: {
card1: {
number: {
type: 'invalid' // The field is invalid
},
cvc: {
type: 'incomplete' // The field is not complete
}
},
card2: {
// No issues with card2
}
},
validation: [] // deprecated
}

BasisTheoryApiError

{
name: "BasisTheoryApiError",
data: {
// Full API response body from Basis Theory
},
status: 400 // HTTP status code
}

HttpClientError

{
name: "HttpClientError",
data: {
// Response body from the third-party API
},
status: 400, // HTTP status code
headers: {
// Response headers from the third-party API
}
}
You can check the error name property as an alternative to using instanceof for type checking.
The response from this service is the actual plaintext data. It may contain sensitive data depending on the third-party API response.

If you encounter issues during tokenization such as timeout errors or validation failures, refer to our troubleshooting guide for detailed solutions.