Skip to main content

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:

FieldTypeDescription
typestringToken type (e.g. 'card', 'token')
dataobjectData payload — may contain element references at any depth
metadataRecord<string, string>Non-sensitive key/value pairs stored with the token
containersstring[]Container paths that restrict access to this token
maskobjectMasking expression for the token response
aliasesstring[]Alternate IDs for the token
search_indexesstring[]Fields to index for search
fingerprint_expressionstringExpression used to generate the token fingerprint
expires_atstringISO 8601 expiration timestamp

Response (TokenizeResult):

FieldTypeDescription
idstringToken ID — safe to store and send to your backend
type'card' | 'token'Token type
maskstringMasked representation of the data
brandstringCard brand (card tokens only)
expiry{ month: number; year: number }Expiry (card tokens only)
metadataobjectMetadata stored with the token
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);
}

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
});
Never call 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:

FieldTypeDescription
noncestringOne-time nonce — send to your backend to authorize the session
expires_atstringISO 8601 expiration timestamp
Sessions are the correct mechanism for revealing tokenized data to a user (e.g., showing a saved card). The session nonce must be authorized server-side — it cannot be used directly from the frontend.

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).