Skip to main content

Stripe Forward

A single endpoint, POST /connections/stripe-forward/tokenize, that accepts forwarded payment-method data from Stripe's Forwarding API and creates the appropriate Basis Theory resource:

Forwarded payment methodwallet_typeResource created
Card (FPAN)absentToken of type card
Apple Pay™ DPANapple_payApple Pay™ resource
Google Pay™ DPAN (CRYPTOGRAM_3DS)google_payGoogle Pay™ resource
Google Pay™ FPAN (PAN_ONLY)absentToken of type card

See Choosing the wallet type below for guidance on selecting the right shape for each Stripe Payment Method.

Tokenize a Card

Endpoint conforming to Stripe's API contract to use their Forwarding API and create a card token.

This endpoint differs from the Create Token endpoint by conforming to Stripe's Forwarding API contract: card contains Stripe's payment method details, and metadata contains any Basis Theory specific token attributes that were specified when calling the Forwarding API.

The card object will then be transformed to the Basis Theory's card token data, so any expression used in the original request to the Forwarding API referring to card data must reference the final transformed data object as shown in the example request below. Specifically, in line 16 when referencing the card's expiration month, it is data.expiration_month and not card.exp_month.

{
"data": {
"number": "...",
"expiration_month": "...",
"expiration_year": "...",
"name": "..."
}
}
POST
https://api.basistheory.com/connections/stripe-forward/tokenize
Copy

Permissions

token:create

Request

curl "https://api.basistheory.com/connections/stripe-forward/tokenize" \
-H "BT-API-KEY: <API_KEY>" \
-H "Content-Type: application/json" \
-X "POST" \
-d '{
"card": {
"number": "4242424242424242",
"exp_month": "07",
"exp_year": "2030",
"cvc": "123",
"name": "John Doe"
},
"metadata": {
"mask": {
"number": "{{ data.number | reveal_last: 4 }}",
"expiration_month": "{{ data.expiration_month }}",
"expiration_year": "{{ data.expiration_year }}",
"name": "{{ data.name }}"
},
"containers": [ "/pci/high/" ],
"metadata": {
"nonSensitiveField": "Non-Sensitive Value"
},
"search_indexes": [
"{{ data.number | last4 }}"
],
"fingerprint_expression": "{{ data.number }}",
"deduplicate_token": true,
"expires_at": "8/26/2030 7:23:57 PM -07:00"
}
}'

Request Parameters

AttributeRequiredTypeDefaultDescription
cardtrueStripe CardnullThe card details to tokenize.
metadatafalseStripe MetadatanullBasis Theory's token attributes used when creating the card token.

Stripe Card

AttributeRequiredTypeDefaultDescription
numbertruestringnullThe card number without any separators
exp_monthfalsestringnullTwo-digit string representing the card's expiration month
exp_yearfalsestringnullFour-digit string representing the card's expiration year
cvcfalsestringnullThree or four-digit card verification code with automatic expiration
namefalsestringnullThe Cardholder Name

Stripe Metadata

AttributeRequiredTypeDefaultDescription
idfalsestringnullA value or expression specifying the token's ID. If not specified, a UUID will be assigned.
maskfalseanyDepends on the token typeToken data mask. Can be an object, array, or any primitive type such as an integer, boolean, or string. See mask expressions.
containersfalsearrayDepends on the token typeArray of containers to place this token within. Each container is a path representing a logical grouping of tokens. See Token Containers for details.
metadatafalsemap<string, string>nullA key-value map of strings containing non-sensitive data.
search_indexesfalsearraynullArray of expressions used to generate indexes to be able to search against.
fingerprint_expressionfalsestring{{ data | stringify }}Expressions used to fingerprint your token.
deduplicate_tokenfalseboolnullWhether the token is deduplicated on creation.
expires_atfalsestringnullISO8601 compatible Token expiration DateTime. See Token Expiration for more details.
Never reveal sensitive information in the id of your token. See the documentation on Aliasing to learn more about best practices when specifying your own token ID.
Never store sensitive plaintext information in the metadata of your token.

Response

Returns a token if the token was created. Returns an error if there were validation errors, or the token failed to create.

{
"id": "c06d0789-0a38-40be-b7cc-c28a718f76f1",
"tenant_id": "77cb0024-123e-41a8-8ff8-a3d5a0fa8a08",
"type": "card",
"data": {
"number": "XXXXXXXXXXXX4242",
"expiration_month": "07",
"expiration_year": "2030",
"name": "John Doe"
},
"mask": {
"number": "{{ data.number | reveal_last: 4 }}",
"expiration_month": "{{ data.expiration_month }}",
"expiration_year": "{{ data.expiration_year }}",
"name": "{{ data.name }}"
},
"containers": ["/pci/high/"],
"metadata": {
"nonSensitiveField": "Non-Sensitive Value"
},
"search_indexes": ["{{ data.number | last4 }}"],
"fingerprint": "2W6iy15GJoqj5V696BnsadZVTst5fjJf24iW9Kg6hFDa",
"fingerprint_expression": "{{ data.number }}",
"created_by": "fb124bba-f90d-45f0-9a59-5edca27b3b4a",
"created_at": "2020-09-15T15:53:00+00:00",
"expires_at": "2030-08-26T19:23:57-07:00"
}
For security reasons, the data and metadata attributes are redacted from the response when a token is deduplicated, unless the API Key has token:read permission in the targeted container. Click here to learn more about this behavior.

Tokenize a Wallet DPAN

The same endpoint also accepts Apple Pay™ and Google Pay™ Device Primary Account Numbers (DPANs) forwarded from Stripe, so you can migrate stored wallet credentials off Stripe alongside your card volume using a single destination URL.

Instead of a card block, the request body carries wallet_type and a payment_method.network_token block. The endpoint creates the corresponding wallet resource — an Apple Pay™ resource or a Google Pay™ resource — with ingest_source set to stripe_forward.

POST
https://api.basistheory.com/connections/stripe-forward/tokenize
Copy

Permissions

The application must hold token:create and the creator permission for the wallet being tokenized: apple-pay:create for wallet_type = "apple_pay", or google-pay:create for wallet_type = "google_pay".

token:create apple-pay:create google-pay:create

Choosing the wallet type

Inspect card.wallet.type on Stripe's Payment Method object to decide which shape to forward. Apple Pay™ payment methods are always DPAN, so the wallet.type value is sufficient. Google Pay™ payment methods can be either DPAN or FPAN — check card.wallet.google_pay.tokenization_type to distinguish.

Stripe card.wallet.typetokenization_typeForward as
apple_payN/A — Apple Pay™ is always DPANWallet DPAN with wallet_type = "apple_pay"
google_paydpan_or_ecommerce_token (DPAN)Wallet DPAN with wallet_type = "google_pay"
google_payfpan (FPAN)Card, no wallet_type
absent (non-wallet card)Card, no wallet_type

Google Pay™ FPANs forwarded as a card produce a regular Token of type card, not a Google Pay™ resource — an FPAN carries no wallet provenance and is indistinguishable from a non-wallet card on the network.

Request

curl "https://api.basistheory.com/connections/stripe-forward/tokenize" \
-H "BT-API-KEY: <API_KEY>" \
-H "Content-Type: application/json" \
-X "POST" \
-d '{
"wallet_type": "apple_pay",
"payment_method": {
"network_token": {
"number": "4111111111111111",
"cryptogram": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"exp_month": "12",
"exp_year": "2030",
"electronic_commerce_indicator": "07"
}
}
}'

Request Parameters

AttributeRequiredTypeDefaultDescription
wallet_typetruestringnullIdentifies which wallet the DPAN belongs to. Must be exactly apple_pay or google_pay — case-sensitive, no surrounding whitespace.
payment_methodtrueStripe Payment MethodnullThe forwarded payment-method block containing the network token.

A request must include exactly one of card or payment_method.network_token. Sending both, neither, or payment_method without a network_token returns 400.

Stripe Payment Method

AttributeRequiredTypeDefaultDescription
network_tokentrueStripe Network TokennullThe wallet network token to tokenize.

Stripe Network Token

AttributeRequiredTypeDefaultDescription
numbertruestringnullThe DPAN. 13–19 digits, no separators.
exp_monthtruestringnullTwo-digit string representing the DPAN's expiration month (0112).
exp_yeartruestringnullFour-digit string representing the DPAN's expiration year. Must be in the future.
cryptogramfalsestringnullThe 3DS cryptogram from the wallet. Up to 64 characters. Single-use and not retained on the resource.
electronic_commerce_indicatorfalsestringnullTwo-digit ECI value (e.g. 07).

The DPAN cryptogram is single-use and cannot be replayed. It is not retained on the wallet resource and is never returned in any response or webhook payload.

Response

Returns the wallet resource that was created, with a 201 Created status. The response shape depends on wallet_type.

{
"id": "c2995d93-600a-44a2-b6f1-2c25e46603a9",
"type": "dpan",
"tenant_id": "0def1587-e30b-44b7-ad3f-484b323a3917",
"status": "active",
"ingest_source": "stripe_forward",
"expires_at": "2030-12-31T00:00:00+00:00",
"created_by": "0a6475a5-4bb8-4165-8c31-7fbc058843bf",
"created_at": "2026-05-18T16:19:50.9013495+00:00",
"fingerprint": "7bAjvyqJqfPc4jRjniEk87vNrjR74Xax1HnMREWsTiMz",
"card": {
"bin": "411111",
"last4": "1111",
"expiration_month": 12,
"expiration_year": 2030,
"brand": "visa",
"funding": "credit"
},
"authentication": {
"threeds_cryptogram": null,
"eci_indicator": "07"
}
}

See the Apple Pay™ resource reference for the full attribute list. Wallet resources created through this endpoint always have type = "dpan" and ingest_source = "stripe_forward". threeds_cryptogram is always null on the response.

The fingerprint is derived from the DPAN, so the same wallet credential tokenized through Stripe Forward and through POST /apple-pay or POST /google-pay will produce matching fingerprints — use it to detect duplicates across ingest paths.

Errors

Status CodeDescription
400The request body is malformed — both card and payment_method.network_token present, neither present, wallet_type invalid, or network_token fields invalid.
401Missing or invalid API key.
403The application is missing the wallet-specific creator permission: apple-pay:create for wallet_type = "apple_pay", google-pay:create for wallet_type = "google_pay".