Services
Services let you tokenize, retrieve, update, encrypt, and manage sensitive data collected by elements. Raw values never pass through your application — the SDK resolves element references directly from the secure iframe when it sends requests to the Basis Theory API.
How element references work
When you pass an element instance anywhere in a service call's data object, the SDK replaces it with the actual sensitive value at request time. Your code only ever holds an element reference — never the raw value.
const token = await bt.tokens.create({
type: 'card',
data: {
number: cardNumberEl, // ← element reference, not a string
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});
// token.id is all you get back — the PAN is never in this scope
console.log(token.id);
You can mix element references with plain values freely:
await bt.tokens.create({
type: 'token',
data: {
ssn: ssnElement, // sensitive — resolved from iframe
name: 'Jane Smith', // plain — sent as-is
account_id: '12345', // plain — sent as-is
},
metadata: {
source: 'checkout',
},
});
tokens.create
Creates a persistent token. Accepts element references in data at any depth.
const token = await bt.tokens.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});
console.log(token.id); // 'tok_...'
console.log(token.type); // 'card'
Request options:
| Field | Type | Description |
|---|---|---|
type | string | Token type (e.g. 'card', 'token') |
data | object | Data payload — may contain element references at any depth |
metadata | Record<string, string> | Non-sensitive key/value pairs stored with the token |
containers | string[] | Container paths that restrict access to this token |
mask | object | Masking expression for the token response |
aliases | string[] | Alternate IDs for the token |
search_indexes | string[] | Fields to index for search |
fingerprint_expression | string | Expression used to generate the token fingerprint |
expires_at | string | ISO 8601 expiration timestamp |
Response (TokenizeResult):
| Field | Type | Description |
|---|---|---|
id | string | Token ID — safe to store and send to your backend |
type | 'card' | 'token' | Token type |
mask | string | Masked representation of the data |
brand | string | Card brand (card tokens only) |
expiry | { month: number; year: number } | Expiry (card tokens only) |
metadata | object | Metadata stored with the token |
- Web Elements
- React Elements
try {
const token = await bt.tokens.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
metadata: { source: 'checkout' },
});
await sendToBackend(token.id);
} catch (err) {
handleError(err);
}
const { bt } = useBasisTheory();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const token = await bt.tokens.create({
type: 'card',
data: {
number: cardNumberRef.current,
expiration_month: expiryRef.current,
expiration_year: expiryRef.current,
cvc: cvvRef.current,
},
});
await sendToBackend(token.id);
} catch (err) {
handleError(err);
}
};
tokenize
Creates multiple tokens in a single request with an arbitrary data shape. The response mirrors the structure you send, with each token replaced by its result.
const result = await bt.tokenize({
card: {
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
},
ssn: {
type: 'token',
data: ssnEl,
},
});
console.log(result.card.id); // card token ID
console.log(result.ssn.id); // SSN token ID
Use tokenize when you need to create several tokens in one round-trip, or when you want to preserve a custom key structure in the response.
tokenIntents.create
Creates a short-lived token intent. Token intents are not persisted as tokens — they are validated server-side and converted to a token by your backend using the Basis Theory API. Use them when you want to validate card data before committing to a full token.
const intent = await bt.tokenIntents.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});
console.log(intent.id); // send this to your backend
Token intents expire quickly. Pass intent.id to your backend, which authorizes it and converts it to a token using the Basis Theory API.
tokenIntents.get
Retrieves an existing token intent by ID. Requires a session API key (see Sessions).
const intent = await bt.tokenIntents.get(intentId, {
apiKey: sessionApiKey,
});
tokens.retrieve
Retrieves a token. By default, returns masked data. To access the raw value, the request must use a session API key authorized by a Private Application on your backend.
const token = await bt.tokens.retrieve(tokenId, {
apiKey: sessionApiKey, // obtained from an authorized session
});
tokens.retrieve with a Public API key to display raw data. Use a session key authorized on your backend — this ensures Basis Theory audit logs capture the access.tokens.update
Updates mutable token fields. The token type is immutable and cannot be changed. Element references are accepted in data.
await bt.tokens.update(tokenId, {
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
metadata: { updated_by: 'user' },
});
tokens.encrypt
Performs client-side JWE encryption using a provided EC public key in PEM format. The SDK uses ECDH-ES key agreement with A256GCM authenticated encryption — you need an EC key (X25519 or P-256), not an RSA key. The encrypted payload never touches the Basis Theory API — it is returned directly to your code for you to handle.
const encrypted = await bt.tokens.encrypt(
{
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
},
publicKeyPEM, // EC public key in PEM format (ECDH-ES + A256GCM)
'key-id-123' // key identifier included in the JWE header
);
console.log(encrypted.encrypted); // JWE compact serialization string
You can also encrypt multiple tokens at once by passing an object:
const result = await bt.tokens.encrypt(
{
card: { type: 'card', data: { number: cardNumberEl, ... } },
ssn: { type: 'token', data: ssnEl },
},
publicKeyPEM,
'key-id-123'
);
console.log(result.card.encrypted);
console.log(result.ssn.encrypted);
sessions.create
Creates a session that grants temporary elevated access to tokenized data. Sessions must be authorized by a Private Application on your backend before they can be used.
// 1. Create a session on the frontend
const session = await bt.sessions.create();
// 2. Send session.nonce to your backend to authorize it
const { apiKey } = await authorizeSessionOnBackend(session.nonce);
// 3. Use the authorized session API key to retrieve sensitive data
const token = await bt.tokens.retrieve(tokenId, { apiKey });
Session response:
| Field | Type | Description |
|---|---|---|
nonce | string | One-time nonce — send to your backend to authorize the session |
expires_at | string | ISO 8601 expiration timestamp |
Error handling
All service methods return promises and reject on failure. Errors follow a consistent shape:
try {
const token = await bt.tokens.create({ ... });
} catch (err) {
if (err.status === 400) {
// Validation error — field-level detail is in err.body.errors
console.error(err.body?.errors);
} else if (err.status === 401) {
// Invalid or expired API key
} else {
// Network error or unexpected failure
console.error(err.message);
}
}
Element validation errors surface before the API call. If an element's value is invalid or incomplete when you call a service, the SDK rejects the promise immediately with a validation error — no network request is made.
// If cardNumberEl has an incomplete or invalid value when this runs,
// the promise rejects synchronously before hitting the API
const token = await bt.tokens.create({
type: 'card',
data: { number: cardNumberEl, ... },
});
API naming conventions
SDK method and property names use JavaScript camelCase and are automatically converted to snake_case when sent to the Basis Theory API. The one exception is tokenize, which accepts snake_case keys directly in the request body (e.g. expiration_month).