Skip to main content

React Agentic

react-agentic

react-agentic

The Basis Theory @basis-theory/react-agentic package provides React components and hooks for building agentic commerce flows. It handles enrollment verification (OTP + passkey creation) and instruction approval (passkey authentication) with pre-built UI components.

HTTPS Required

The card network SDKs used for verification (Visa and Mastercard) require your application to be served over HTTPS, even in development. Verification will fail on plain HTTP.

For local development, we recommend Cloudflare Quick Tunnels to expose your local server over HTTPS with zero configuration:

# Install cloudflared
brew install cloudflared

# Start a quick tunnel pointing to your local dev server
cloudflared tunnel --url http://localhost:3000

This gives you a temporary https://*.trycloudflare.com URL you can use for testing.

Installation

npm install @basis-theory/react-agentic
React v19 / Next.js 16+

If your project uses React v19 or Next.js 16+, add react and react-dom as peer dependencies and use pnpm overrides to resolve version conflicts:

package.json
{
"peerDependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"pnpm": {
"overrides": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
}
}
}

React 16–18 work without modification.

Setup

Wrap your application with the BtAiProvider to authenticate requests using your Public API key:

import { BtAiProvider } from '@basis-theory/react-agentic';

function App() {
return (
<BtAiProvider apiKey="<PUBLIC_API_KEY>">
<YourApp />
</BtAiProvider>
);
}

BtAiProvider Props

PropTypeRequiredDefaultDescription
apiKeystringYes-Basis Theory public API key
environment"production" | "test" | "sandbox"No"production"Environment to use. test and sandbox use mock providers for Visa.
agenticApiUrlstringNo-Override the agentic commerce API base URL
passkeyTimeoutMsnumberNo60000Timeout in milliseconds for Visa passkey authentication. Increase if users need more time to complete passkey prompts.
sessionReadyTimeoutMsnumberNo10000Timeout in milliseconds for Visa session readiness after refresh.
onNewDevice"decline" | "reenroll"No"reenroll"Behavior when instruction verification detects the consumer is on a different device than the one used during enrollment. "decline" shows an error asking the user to return to the original device. "reenroll" prompts the user to re-enroll the card on the current device.
themeobjectNoDark themePartial theme overrides for the built-in verification modals. Deep-merged with the default dark theme — only override what you need. See Theming.

In the test environment, the SDK uses a mock Visa SDK and validates real SDK configurations in the background, logging warnings if production setup has issues. This lets you develop locally without HTTPS while still catching configuration problems early.

Hooks

useAgentic

The useAgentic hook provides methods for enrollment verification, instruction approval, and SDK status. It must be used within a BtAiProvider.

import { useAgentic } from '@basis-theory/react-agentic';

function MyComponent() {
const {
ready,
verifyEnrollment,
verifyInstruction,
getStatus,
updateApiKey,
} = useAgentic();

// ...
}

Return Values

PropertyTypeDescription
readybooleantrue when the SDK is initialized and ready for verification calls. On HTTPS, both Visa and Mastercard SDKs must be ready. On localhost, Mastercard-only is accepted since Visa requires HTTPS.
verifyEnrollment(enrollmentId: string) => PromiseOpens a modal for enrollment verification. Safe to call before ready — it waits automatically.
verifyInstruction(agentId: string, instructionId: string) => PromiseOpens a modal for instruction verification. Safe to call before ready — it waits automatically.
getStatus() => { visa: boolean, mastercard: boolean }Returns per-network SDK readiness status.
updateApiKey(newApiKey: string) => voidDynamically changes the API key, triggering re-initialization.
apiKeystringThe current API key.
environmentstringThe current environment.

verifyEnrollment

Renders a modal that guides the consumer through OTP verification and passkey creation to verify card enrollment.

const result = await verifyEnrollment(enrollmentId);
ParameterTypeDescription
enrollmentIdstringThe enrollment ID to verify

See the Agentic Credentials guide for a complete usage example.

If verification fails and the user closes the modal, the promise rejects with an error that includes error details (traceId, debug, code, status) when available:

try {
const result = await verifyEnrollment(enrollmentId);
} catch (error) {
console.error(error.message); // Human-readable error message
console.error(error.traceId); // BT-TRACE-ID for support
console.error(error.code); // Error code (e.g., "PROVIDER_VERIFICATION_FAILED")
}

verifyInstruction

Renders a modal for passkey authentication to approve a spending instruction.

const result = await verifyInstruction(agentId, instructionId);
ParameterTypeDescription
agentIdstringThe agent ID
instructionIdstringThe instruction ID to verify

See the Agentic Credentials guide for a complete usage example.

If verification fails and the user closes the modal, the rejected error includes the same error details as verifyEnrollment.

useEnrollmentVerification

Action-based hook for building a custom enrollment verification UI. Render your UI based on status and call the corresponding action to advance the flow. Use this instead of verifyEnrollment() when you need full control over the verification experience.

The hook handles orchestration for both card networks:

  • Visa: OTP method selection → OTP input → passkey creation → completion
  • Mastercard: popup-based authentication → completion
import { useEnrollmentVerification } from '@basis-theory/react-agentic';

function CustomEnrollmentUI({ enrollmentId }) {
const {
status,
error,
otpMethods,
start,
selectOtpMethod,
submitOtp,
confirmPasskey,
retry,
cancel,
} = useEnrollmentVerification({ enrollmentId });

// Render your own UI based on status
}

Input Props

PropTypeRequiredDescription
enrollmentIdstringYesThe enrollment ID to verify

Statuses

StatusDescriptionAvailable Actions
idleNot startedstart()
loadingAsync operation in progress
otp_requiredShow OTP method picker (otpMethods available)selectOtpMethod(methodId)
otp_sentShow OTP code inputsubmitOtp(code)
passkey_requiredVisa passkey creation neededconfirmPasskey()
popup_requiredMastercard popup neededconfirmPasskey(), retry()
verifiedVerification complete
errorSomething went wrong (error has message)retry(), start()

Return Values

PropertyTypeDescription
statusstringCurrent status (see table above)
errorstring | nullError message when status is error
errorDetailsobject | nullStructured error info when status is error. See error details object.
otpMethodsarrayAvailable OTP delivery methods when status is otp_required
start() => PromiseBegin or restart the verification flow
selectOtpMethod(methodId: string) => PromiseSelect an OTP delivery method
submitOtp(code: string) => PromiseSubmit the OTP code
confirmPasskey() => PromiseTrigger passkey creation (Visa) or popup authentication (Mastercard)
retry() => PromiseRetry the current step
cancel() => voidCancel and reset to idle

How to Build Your Own UI

  1. Call start() to kick off the enrollment verification flow.
  2. Switch on status to render the appropriate UI for each step:
    • loading — show a spinner or loading indicator
    • otp_required — render a list or buttons from otpMethods and call selectOtpMethod(methodId) on selection
    • otp_sent — render a code input field and call submitOtp(code) on submit
    • passkey_required — show a prompt explaining passkey creation and call confirmPasskey()
    • popup_required — show a prompt explaining Mastercard popup auth and call confirmPasskey()
    • verified — show a success message and proceed with your app flow
    • error — display the error message with a button to retry() or start() again
  3. Use cancel() to let the user abort and reset to idle at any point.

The hook manages all card-network orchestration internally — you only need to render UI and call actions.

useInstructionVerification

Action-based hook for building a custom instruction verification UI. Render your UI based on status and call the corresponding action to advance the flow. Use this instead of verifyInstruction() when you need full control over the verification experience.

The hook handles authentication for both card networks:

  • Visa: passkey authentication → completion
  • Mastercard: popup-based authentication → completion
import { useInstructionVerification } from '@basis-theory/react-agentic';

function CustomInstructionUI({ agentId, instructionId }) {
const {
status,
error,
start,
confirmPasskey,
retry,
cancel,
} = useInstructionVerification({ agentId, instructionId });

// Render your own UI based on status
}

Input Props

PropTypeRequiredDescription
agentIdstringYesThe agent ID
instructionIdstringYesThe instruction ID to verify
onNewDevice"decline" | "reenroll"NoBehavior when a cross-device passkey mismatch is detected. Defaults to the value set on BtAiProvider.

Statuses

StatusDescriptionAvailable Actions
idleNot startedstart()
loadingAsync operation in progress
passkey_requiredVisa passkey auth neededconfirmPasskey()
popup_requiredMastercard popup neededconfirmPasskey(), retry()
verifiedVerification complete
new_device_declineCross-device mismatch detected, onNewDevice is "decline"cancel()
new_device_reenrollCross-device mismatch detected, onNewDevice is "reenroll"cancel()
errorSomething went wrong (error has message)retry(), start()

Return Values

PropertyTypeDescription
statusstringCurrent status (see table above)
errorstring | nullError message when status is error, new_device_decline, or new_device_reenroll
errorDetailsobject | nullStructured error info when status is error. See error details object.
start() => PromiseBegin or restart the verification flow
confirmPasskey() => PromiseTrigger passkey auth (Visa) or popup authentication (Mastercard)
retry() => PromiseRetry the current step
cancel() => voidCancel and reset to idle

How to Build Your Own UI

  1. Call start() to kick off the instruction verification flow.
  2. Switch on status to render the appropriate UI for each step:
    • loading — show a spinner or loading indicator
    • passkey_required — show a prompt explaining Visa passkey authentication and call confirmPasskey()
    • popup_required — show a prompt explaining Mastercard popup auth and call confirmPasskey()
    • verified — show a success message and proceed with your app flow
    • new_device_decline — inform the user that the card was enrolled on a different device and they must use the original device or re-enroll
    • new_device_reenroll — prompt the user to re-enroll the card on the current device
    • error — display the error message with a button to retry() or start() again. Check errorDetails for trace IDs when reporting issues.
  3. Use cancel() to let the user abort and reset to idle at any point.

The hook manages all card-network orchestration internally — you only need to render UI and call actions.

Error Details Object

When a verification hook enters the error status due to an API error, errorDetails provides structured information for debugging. It is null for non-API errors.

PropertyTypeDescription
traceIdstring | nullThe BT-TRACE-ID response header from the failed API call. Include this when contacting support.
debugobject | nullAdditional debug information from the API error response (e.g., provider correlation IDs).
codestring | nullThe error code from the API (e.g., PROVIDER_VERIFICATION_FAILED). See error codes.
statusnumber | nullThe HTTP status code of the failed response.

errorDetails is cleared automatically when a new action is called (e.g., start(), retry(), cancel()).

Theming

The built-in verification modals use a design token system that you can customize via the theme prop on BtAiProvider. Pass a partial theme object — unset tokens fall back to the default dark theme.

Light theme example
import { BtAiProvider } from '@basis-theory/react-agentic';

function App() {
return (
<BtAiProvider
apiKey="<PUBLIC_API_KEY>"
theme={{
colors: {
primary: '#1a1a1a',
text: {
primary: '#1a1a1a',
secondary: '#6b7280',
},
background: {
overlay: 'rgba(0, 0, 0, 0.5)',
surface: '#ffffff',
input: '#f9fafb',
button: {
primary: '#1a1a1a',
primaryText: '#ffffff',
},
},
border: {
default: '#d1d5db',
focus: '#1a1a1a',
},
},
}}
>
<YourApp />
</BtAiProvider>
);
}

You can also import defaultTheme to inspect the full token structure:

import { defaultTheme } from '@basis-theory/react-agentic';
console.log(defaultTheme);

Theme Tokens

The theme object supports the following token categories. All tokens are optional — only override what you need.

colors

TokenDefaultDescription
primary#f4f4f5Primary accent color
error#ef4444Error state color
success#10b981Success state color
text.primary#ffffffPrimary text color
text.secondary#a1a1aaSecondary/muted text color
text.placeholder#71717aInput placeholder text color
text.error#fca5a5Error message text color
background.overlayrgba(0,0,0,0.85)Modal backdrop overlay
background.surfacergba(13,13,15,1)Modal surface background
background.input#18181bInput field background
background.cardrgba(23,23,26,1)Card/panel background
background.button.primary#f4f4f5Primary button background
background.button.primaryText#000000Primary button text color
background.button.secondaryrgba(255,255,255,0.1)Secondary button background
background.button.secondaryText#ffffffSecondary button text color
background.button.disabled#52525bDisabled button background
border.default#52525bDefault border color
border.focus#f4f4f5Focused input border color
border.modalrgba(255,255,255,0.1)Modal border color
border.errorrgba(239,68,68,0.3)Error state border color
spinner.trackrgba(244,244,245,0.3)Loading spinner track color
spinner.indicatorrgba(244,244,245,1)Loading spinner indicator color

typography

TokenDefaultDescription
fontFamilyInter, -apple-system, ...Primary font stack
fontSize.title24pxModal title font size
fontSize.body14pxBody text font size
fontSize.small12pxSmall text font size
fontSize.input18pxOTP input font size
fontWeight.normal400Normal font weight
fontWeight.medium500Medium font weight
fontWeight.semibold600Semibold font weight

borders

TokenDefaultDescription
radius.modal8pxModal border radius
radius.input8pxInput field border radius
radius.button8pxButton border radius
radius.option8pxOTP method option border radius

spacing

TokenDefaultDescription
modal32pxModal internal padding
section16pxSection spacing
input8pxInput element spacing
buttonGap8pxGap between buttons