API Checkout

Learn how to automate API-driven checkout flows using virtual cards, network tokens, or raw credit card data through BT AI’s secure proxy system. This guide covers different credential types for API integration based on your merchant’s capabilities.

Overview

Basis Theory AI enabels the generation and use of different types of credentials for API-based transactions. Choose the appropriate credential type based on your target API’s capabilities:

  • Virtual Card: Generate a virtual card for APIs that accept standard card data
  • Network Token: Generate a network token for APIs that support tokenized payments
  • Raw Credit Card: Use the original card data through BT AI’s secure proxy when no other option works

Prerequisites

Before implementing API checkout, ensure you have:

Successfully Implemented Payment Method Collection

You must have completed the Collecting Payment Methods guide and successfully created at least one Payment Method. This guide assumes you have:

  • A working JWT creation system for both public and private roles
  • Successfully implemented the card collection flow
  • At least one card type Payment Method available for your entity
  • The Payment Method ID from your collection implementation

Using Virtual Card with an API

When your target API accepts standard credit card data (it should also accept a Virtual Card), you can generate a virtual card credential to forward to the API for transaction completion.

Creating a Purchase Intent from the Backend

Generate Private JWT for Backend Access

import { jwt } from '@basistheory/ai-sdk';
 
// Generate private JWT for backend operations
const privateJWT = jwt.generatePrivate(
  privateKey, 
  externalId, 
  expiration = '1m'
);

Request Purchase Intent Creation

To generate a virtual card credential for API integration, you’ll need to create a Purchase Intent from your backend. This requires sending the details outlined in the Create Purchase Intent API.

curl -X POST \
  https://api.basistheory.ai/tenants/your-tenant-id/purchase-intent \
  -H 'Authorization: Bearer your-private-jwt-token' \
  -H 'Content-Type: application/json' \
  -d '{
    "credentialType": "virtual-card",
    "paymentMethodId": "26859380-7829-4ee1-8a0a-38927881e7ef",
    "mandates": [
      {
        "type": "maxAmount",
        "value": "100",
      },
      {
        "type": "currency",
        "value": "USD"
      }
      {
        "type": "mcc",
        "value": "444"
      }
    ]
  }'

Handle Purchase Intent Response

The response will determine your next steps. The Purchase Intent can return in two states:

Active State (Ready to Use)

If the response status is "active", you immediately have access to the virtual card credential:

{
  "id": "0b1ac700-c1a7-46b0-a166-809e5aac4dc3",
  "entityId": "94c94330-94fd-4832-a106-e8474a274fe4",
  "credentialType": "virtual-card",
  "status": "active",
  "card": {
    "number": "2222030198005808",
    "expirationMonth": "07",
    "expirationYear": "2028",
    "cvc": "211"
  },
  "createdAt": "2025-06-16T14:00:00Z",
  "expiresAt": "2025-06-13T18:42:01Z"
}
Verify State (Verification Required)

If the response status is "verify", additional verification is required:

{
  "id": "46c029d2-485a-4928-83b5-4326c4866722",
  "entityId": "94c94330-94fd-4832-a106-e8474a274fe4",
  "credentialType": "virtual-card",
  "status": "verify",
  "createdAt": "2025-06-16T14:00:00Z",
  "expiresAt": "2025-06-13T18:42:01Z"
}

Verify the Purchase Intent

When a Purchase Intent requires verification (status: "verify"), you’ll need to use the frontend SDK to complete the verification process. This ensures network requirements are met to verify ownership of the Payment Method.

Generate a JWT in Backend

Assuming you no longer have an active JWT from collecting the Payment Method, you’ll need to generate a JWT in your backend to grant your frontend SDK access.

import { jwt } from '@basistheory/ai-sdk';
 
const jwt = jwt.generatePublic(privateKey, externalId, expiration = '1m');

Frontend Verification Flow

You’ll now use this JWT to initiate the verification steps for this Purchase Intent. Depending on the network - this may take form of the following, all of which are handled seamlessly with our verifyPurchaseIntent function:

  • Token and Device binding
  • 2FA text message, email, or mobile verification
  • Passkey setup and binding to device
import { btAi } from '@btai/js-sdk';
 
// ... get signed jwt from your backend
 
// initialize sdk
const btAi = await btAi.init(jwt);
const purchaseIntent = await verifyPurchaseIntent("tenant_1234", "purchase_intent_1234");

Verification Flow Experience

The verification process ensures network requirements are met and may include several steps:

Verification Steps Include:

  • Two-Factor Authentication: SMS or authenticator app verification
  • Passkey Setup: Biometric authentication setup for future use
  • Network Verification: Card network-specific verification requirements
  • Device Registration: Secure device binding for future transactions
Visa Two-Factor Authentication Flow

2FA Verification

Visa Passkey Setup Flow

Passkey Setup

Once the verification promise resolves, the verification has succeeded and your backend can now request the credentials.

Get the Credential from Purchase Intent

After verification is complete, your backend needs to retrieve the now-active credential using a private JWT:

Request Purchase Intent to Get Credential

Once verification is complete, retrieve the activated Purchase Intent with credentials:

curl -X GET \
  https://api.basistheory.ai/tenants/:tenant_id/purchase-intent/46c029d2-485a-4928-83b5-4326c4866722 \
  -H 'Authorization: Bearer your-private-jwt-token'

Successful Response with Virtual Card:

{
  "id": "0b1ac700-c1a7-46b0-a166-809e5aac4dc3",
  "entityId": "94c94330-94fd-4832-a106-e8474a274fe4",
  "credentialType": "virtual-card",
  "status": "active",
  "card": {
    "number": "2222030198005808",
    "expirationMonth": "07",
    "expirationYear": "2028",
    "cvc": "211"
  },
  "createdAt": "2025-06-16T14:00:00Z",
  "expiresAt": "2025-06-13T18:42:01Z"
}

Use Virtual Card with Target API

Once you have the virtual card credentials, forward them to your target API:

// Forward virtual card to target API
const response = await fetch('https://api.merchant.com/payments', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    amount: 1000,
    currency: 'usd',
    card: {
      number: purchaseIntent.card.number,
      exp_month: purchaseIntent.card.expirationMonth,
      exp_year: purchaseIntent.card.expirationYear,
      cvc: purchaseIntent.card.cvc
    }
  })
});

Using a Network Token with an API

When your target API supports tokenized payments, you can generate a network token credential for enhanced security.

Request Purchase Intent Creation

curl -X POST \
  https://api.basistheory.ai/tenants/your-tenant-id/purchase-intent \
  -H 'Authorization: Bearer your-private-jwt-token' \
  -H 'Content-Type: application/json' \
  -d '{
    "credentialType": "network-token",
    "paymentMethodId": "26859380-7829-4ee1-8a0a-38927881e7ef",
    "mandates": [
      {
        "type": "maxAmount",
        "value": "100"
      },
      {
        "type": "currency",
        "value": "USD"
      },
      {
        "type": "mcc",
        "value": "444"
      }
    ]
  }'

Handle Network Token Response

Most likely your Network Token will require no additional verification, although if it were to require it - you will follow the same steps as laid out in the Virtual Card steps above.

Active State:

{
  "id": "46c029d2-485a-4928-83b5-4326c4866722",
  "credentialType": "network-token",
  "status": "active",
  "token": {
    "number": "2222030198005808",
    "expirationMonth": "07",
    "expirationYear": "2028",
    "cryptogram": "AAnSCQ9UvB3WAA4IVFwEAAADFA=="
  }
}

Use Network Token with Target API

// Forward network token to target API
const response = await fetch('https://api.merchant.com/payments', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    amount: 1000,
    currency: 'usd',
    payment_method: {
      type: 'network_token',
      token: {
        number: purchaseIntent.token.number,
        cryptogram: purchaseIntent.token.cryptogram,
        exp_month: purchaseIntent.token.expirationMonth,
        exp_year: purchaseIntent.token.expirationYear
      }
    }
  })
});

Using Raw Credit Card with an API

When no other credential option works (or have failed), you can use the original card data through BT AI’s secure proxy system for maximum compatibility.

Generate Private JWT for Proxy Access

import { jwt } from '@basistheory/ai-sdk';
 
const privateJWT = jwt.generatePrivate(
  privateKey, 
  externalId, 
  expiration = '1m'
);

Use Proxy Request

curl -X POST \
  https://api.basistheory.ai/tenants/your-tenant-id/proxy \
  -H 'BT-Authorization: Bearer your-private-jwt-token' \
  -H 'BT-Target-URL: https://api.merchant.com/payments' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": 1000,
    "currency": "usd",
    "payment_method": {
      "type": "card",
      "card": {
        "number": "{{ paymentMethod: 815029c2-29ec-4fc2-8cd4-99feb3ee582c | type: '\''pan'\'' | json: '\''$.number'\'' }}",
        "exp_month": "{{ paymentMethod: 815029c2-29ec-4fc2-8cd4-99feb3ee582c | type: '\''pan'\'' | json: '\''$.expirationMonth'\'' }}",
        "exp_year": "{{ paymentMethod: 815029c2-29ec-4fc2-8cd4-99feb3ee582c | type: '\''pan'\'' | json: '\''$.expirationYear'\'' }}",
        "cvc": "{{ paymentMethod: 815029c2-29ec-4fc2-8cd4-99feb3ee582c | type: '\''pan'\'' | json: '\''$.cvc'\'' }}"
      }
    }
  }'

Next Steps

🎉 Outstanding! You’ve successfully implemented API checkout with BT AI. You now have three different approaches for API integration based on your target system’s capabilities: