Enrollments
Enrollments link a Basis Theory card token to an agent through a network provider (Visa or Mastercard). During enrollment, the card brand is auto-detected and the card is registered with the corresponding network. The consumer must verify ownership before the enrollment can be used.
Authentication
All requests require a BT-API-KEY header with your Basis Theory API key.
All errors follow the standard error response format.
List Enrollments
Returns a paginated list of enrollments for your tenant.
Permissions
enrollment:get
Request
curl 'https://api.basistheory.com/agentic/enrollments?limit=25' \
-H 'BT-API-KEY: <BT_API_KEY>'
Request Parameters
| Attribute | Required | Type | Description |
|---|---|---|---|
limit | No | integer | Number of results to return (default: 25, max: 100) |
cursor | No | string | Opaque pagination cursor from a previous response |
Response
Returns a paginated list of enrollment objects.
{
"data": [
{
"id": "enr_wNe75VKdzvojI9iD5fJxr",
"provider": "visa",
"status": "active",
"card": {
"brand": "visa",
"bin": "424032",
"last4": "0359",
"expiration_month": 11,
"expiration_year": 2029,
"display": {
"art_url": "https://assets.vims.visa.com/vims/cardart/abc123",
"background_color": "1A1F71",
"foreground_color": "FFFFFF",
"description": "Visa Signature",
"issuer_name": "Chase"
}
},
"created_at": "2026-01-15T10:31:00Z"
}
],
"pagination": {
"next_cursor": "eyJpZCI6ImVucl93TmU3NVZLZHp2b2pJOWlENWZKeHIifQ",
"has_more": false
}
}
Create Enrollment
Enrolls a card with a network provider. The card brand is auto-detected from the Basis Theory token data.
Permissions
enrollment:create
Request
curl -X POST https://api.basistheory.com/agentic/enrollments \
-H 'BT-API-KEY: <BT_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"token_id": "<TOKEN_ID>",
"consumer": {
"email": "consumer@example.com",
"id": "user-123",
"country_code": "US",
"language_code": "en"
},
"agent_ids": ["<AGENT_ID_1>", "<AGENT_ID_2>"]
}'
Request Parameters
| Attribute | Required | Type | Description |
|---|---|---|---|
token_id | Yes | string | The Basis Theory card token ID |
consumer | Yes | object | The consumer object |
agent_id | No | string | Associate the enrollment with a single agent. Mutually exclusive with agent_ids |
agent_ids | No | array | Associate the enrollment with multiple agents (max 50). Mutually exclusive with agent_id. Duplicates are silently deduplicated |
Consumer Object
| Attribute | Required | Type | Description |
|---|---|---|---|
email | Yes | string | The consumer's email address |
id | No | string | An identifier for the consumer in your system |
country_code | No | string | ISO 3166-1 alpha-2 country code (default: US) |
language_code | No | string | Language code (default: en) |
Response
Returns 201 with an enrollment object if the enrollment succeeds. The enrollment will have pending_verification status until the consumer completes verification.
If the card is successfully registered with the network but a subsequent provider step fails, the API returns 422 with the enrollment in failed status. The response includes an error object describing what went wrong, and card display metadata is still available. Failed enrollments can be retried with the retry endpoint.
{
"id": "enr_wNe75VKdzvojI9iD5fJxr",
"provider": "visa",
"status": "pending_verification",
"card": {
"brand": "visa",
"bin": "424032",
"last4": "0359",
"expiration_month": 11,
"expiration_year": 2029,
"display": {
"art_url": "https://assets.vims.visa.com/vims/cardart/abc123",
"background_color": "1A1F71",
"foreground_color": "FFFFFF",
"description": "Visa Signature",
"issuer_name": "Chase"
}
},
"created_at": "2026-01-15T10:31:00Z"
}
Get Enrollment
Retrieves an enrollment by ID.
Permissions
enrollment:get
Request
curl https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr \
-H 'BT-API-KEY: <BT_API_KEY>'
Request Parameters
| Attribute | Required | Type | Description |
|---|---|---|---|
enrollment_id | Yes | string | The ID of the enrollment to retrieve |
Response
Returns an enrollment object if successful.
{
"id": "enr_wNe75VKdzvojI9iD5fJxr",
"provider": "visa",
"status": "active",
"card": {
"brand": "visa",
"bin": "424032",
"last4": "0359",
"expiration_month": 11,
"expiration_year": 2029,
"display": {
"art_url": "https://assets.vims.visa.com/vims/cardart/abc123",
"background_color": "1A1F71",
"foreground_color": "FFFFFF",
"description": "Visa Signature",
"issuer_name": "Chase"
}
},
"created_at": "2026-01-15T10:31:00Z"
}
Delete Enrollment
Deletes an enrollment.
Permissions
enrollment:delete
Request
curl -X DELETE https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr \
-H 'BT-API-KEY: <BT_API_KEY>'
Request Parameters
| Attribute | Required | Type | Description |
|---|---|---|---|
enrollment_id | Yes | string | The ID of the enrollment to delete |
Response
Returns a 204 No Content response if successful.
Retry Enrollment
Retries a failed enrollment by resuming from the last successful provider step. Only enrollments with failed status can be retried. On success, the enrollment transitions to pending_verification and must be verified before use.
Permissions
enrollment:create
Request
curl -X POST https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr/retry \
-H 'BT-API-KEY: <BT_API_KEY>'
Request Parameters
| Attribute | Required | Type | Description |
|---|---|---|---|
enrollment_id | Yes | string | The ID of the failed enrollment to retry |
Response
Returns 200 with an enrollment object if the retry succeeds. The enrollment status changes to pending_verification.
If the retry fails, returns 422 with the enrollment still in failed status and an updated error object.
Returns ENROLLMENT_NOT_FAILED if the enrollment is not in failed status.
Verify Enrollment
Enrollment verification is a multi-step flow that confirms the consumer owns the card. The @basis-theory/react-agentic SDK handles this entire flow automatically via the verifyEnrollment() method. The individual endpoints are documented below for reference.
verifyEnrollment() method from the @basis-theory/react-agentic SDK's useAgentic hook. It handles the full verification UI including OTP entry and passkey creation. See the Agentic Credentials guide for usage examples.Verification Flow
- Start verification —
POST /enrollments/:id/verify— returns available OTP methods (or auto-approves). - Select method —
POST /enrollments/:id/verify/method— chooses SMS or email for OTP delivery. - Submit OTP —
POST /enrollments/:id/verify/otp— submits the one-time code. - Complete —
POST /enrollments/:id/verify/complete— finalizes verification after passkey creation.
Start Verification
Initiates the enrollment verification flow.
Permissions
enrollment:verify
curl -X POST https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr/verify \
-H 'BT-API-KEY: <BT_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"device_context": {
"screen_height": 1080,
"screen_width": 1920,
"user_agent_string": "Mozilla/5.0 ...",
"language_code": "en-US",
"time_zone": "America/New_York",
"java_script_enabled": true,
"client_device_id": "a1b2c3d4e5f6a1b2c3d4e5f6",
"client_reference_id": "550e8400-e29b-41d4-a716-446655440000",
"platform_type": "WEB",
"ip_address": "192.168.1.1"
}
}'
Device Context Object
| Attribute | Required | Type | Description |
|---|---|---|---|
screen_height | Yes | integer | Screen height in pixels |
screen_width | Yes | integer | Screen width in pixels |
user_agent_string | Yes | string | Browser user agent string |
language_code | Yes | string | Browser language (e.g., en-US) |
time_zone | Yes | string | IANA time zone (e.g., America/New_York) |
java_script_enabled | Yes | boolean | Whether JavaScript is enabled |
client_device_id | Yes | string | Persistent device identifier |
client_reference_id | Yes | string | Unique identifier per verification session |
platform_type | Yes | string | WEB, MOBILE, or NATIVE |
ip_address | No | string | Client IP address (auto-populated from request if omitted) |
color_depth | No | integer | Screen color depth |
accept_header | No | string | Browser accept header |
@basis-theory/react-agentic SDK collects and sends device context automatically. You only need to construct this object if you are calling the verification endpoints directly.Returns either { "status": "approved" } if the enrollment is auto-approved, or a challenge response with available OTP methods:
{
"status": "challenge",
"methods": [
{ "id": "method_sms_001", "type": "sms", "value": "***-***-1234" },
{ "id": "method_email_001", "type": "email", "value": "j***@example.com" }
]
}
Select OTP Method
Selects which method (SMS or email) to use for OTP delivery.
Permissions
enrollment:verify
curl -X POST https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr/verify/method \
-H 'BT-API-KEY: <BT_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"method_id": "method_sms_001"
}'
Returns confirmation that the OTP was sent:
{
"status": "otp_sent",
"method": {
"id": "method_sms_001",
"type": "sms",
"value": "***-***-1234"
}
}
Submit OTP
Submits the one-time code received by the consumer.
Permissions
enrollment:verify
curl -X POST https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr/verify/otp \
-H 'BT-API-KEY: <BT_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"otp_code": "123456"
}'
Returns a verified status if the OTP is correct. May return INVALID_OTP, OTP_EXPIRED, or MAX_ATTEMPTS_EXCEEDED errors.
Complete Verification
Finalizes verification after passkey creation on the consumer's device.
Permissions
enrollment:verify
curl -X POST https://api.basistheory.com/agentic/enrollments/enr_wNe75VKdzvojI9iD5fJxr/verify/complete \
-H 'BT-API-KEY: <BT_API_KEY>'
After successful completion, the enrollment status changes from pending_verification to active.
Enrollment Object
| Attribute | Type | Description |
|---|---|---|
id | string | Unique identifier of the enrollment |
provider | string | The network provider (visa or mastercard) |
status | string | The enrollment status. See enrollment statuses |
card | object | Card display metadata. See card object |
error | object | Present when status is failed. See error object |
created_at | string | ISO 8601 timestamp of when the enrollment was created |
Enrollment Statuses
| Status | Description |
|---|---|
pending_verification | Awaiting consumer verification via OTP and passkey |
active | Consumer verified; enrollment can be used to create instructions |
failed | Enrollment partially failed at the provider. Can be retried. Card display data is still available |
suspended | Suspended by the card network (e.g., card reported lost or stolen) |
deleted | Enrollment has been deleted |
Card Object
| Attribute | Type | Description |
|---|---|---|
brand | string | Card brand (e.g., visa) |
bin | string | Bank identification number (first 6 digits) |
last4 | string | Last four digits of the card number |
expiration_month | integer | Card expiration month |
expiration_year | integer | Card expiration year |
display | object | Card art and display metadata. See display object |
Display Object
Card art and display metadata from the card network.
| Attribute | Type | Description |
|---|---|---|
art_url | string | URL to the card art image |
background_color | string | Hex color code for the card background |
foreground_color | string | Hex color code for the card foreground |
description | string | Card product description (e.g., "Visa Signature") |
issuer_name | string | Name of the card issuer |
Error Object
Included when an enrollment has failed status. Describes what went wrong during enrollment.
| Attribute | Type | Description |
|---|---|---|
type | string | Error code (e.g., PROVIDER_ENROLLMENT_FAILED) |
title | string | Human-readable error title |
status | integer | HTTP status code |
detail | string | Detailed error message |
step | string | The provider step that failed (e.g., vts_provisioning, vic_enrollment) |
Pagination
List endpoints use cursor-based pagination.
| Attribute | Type | Description |
|---|---|---|
pagination.next_cursor | string | Opaque cursor for the next page (absent when no more results) |
pagination.has_more | boolean | Whether there are more results beyond this page |
Pass next_cursor as the cursor query parameter to retrieve the next page.