Forward stored credentials
Beta
Last updated: December 3, 2025
Use the Forward API to enrich a payment request with payment credentials you've stored in the Checkout.com Vault. You can enrich a payment with:
- The billing information stored in a payment instrument or token
- The card details stored in an instrument or token
- The details of a network token
The request is then securely forwarded to your specified third-party API endpoint. For example, you can forward the request to external fraud engines, 3D Secure (3DS) engines, and other payment services providers (PSPs) such as Stripe or Adyen.
Information
To enable forwarding, contact your account manager or request support.
This enables you to:
- Store payment credentials in a single location and use them across multiple PSPs, while remaining PCI compliant.
- Provide additional data to third-party fraud engines.
- Extract stored payment credentials from one client's vault and forward them to another client's vault, if you have a multi-client account structure.
- Provide card-linked offers to an issuer or card network.
Information
You must ensure that the third-party endpoint you forward the request to belongs to a PCI-compliant entity.
You need Checkout.com's JSON Web Key (JWK) to encrypt sensitive request headers using JSON Web Encryption (JWE).
In your terminal, run the following command to retrieve our JWK:
1curl --location 'https://forward.checkout.com/.well-known/jwks' \2--header 'Content-Type: application/json' \
Before you can create a forward request, retrieve the ID for the source of the stored credentials. This can be one of:
- A payment instrument ID you've created and stored in the Vault, prefixed with
src_ - A token ID you've generated, prefixed with
tok_ - A network token ID for a provisioned card, prefixed with
nt_
Information
Tokens expire after 15 minutes. If you want to reuse the credentials in future payments, you can convert a token into a payment instrument.
Call the Forward an API request endpoint.
Authenticate the request using one of the following:
- Public key – If using an API key, we recommend encrypting it first.
- An API key
- An access key – If using OAuth 2.0 authentication
Note
Checkout.com does not store the API keys you provide in encrypted headers. We only use the key to process the request in which it's provided.
In the request body, provide the following:
For a payment instrument or a network token stored as a payment instrument:
source.type– Set toid.source.id– The payment instrument ID (prefixed withsrc_) or token ID (prefixed withnt_)destination_request.url– The third-party endpoint you want to forward the request todestination_request.method– The HTTP method you want to use for the requestdestination_request.headers.raw– The raw HTTP headers you want to include in the requestdestination_request.body– The JSON payload formatted according to the key-value pairs expected by the destination PSP
Optionally:
source.cvv_token– The token ID for the card verification value (CVV), prefixed withtok_source.pin_token– The token ID for the card's personal identification number (PIN), prefixed withtok_
Network tokens enhance transaction security by replacing raw card details. This helps ensure compliance with PCI DSS standards and reduces the risk of fraud.
To process a request which includes network tokens, you must include the forwarding logic that checks they're available and the required fields to forward.
- Set the
network_token.enabledfield totrue. - Set the
network_token.request_cryptogramfield to:true– For customer-initiated transactions (CITs)false– For merchant-initiated transactions (MITs)
If a network token is unavailable, the Forward API falls back to using tokenized card details.
You can use the following placeholder values in the destination_request.body field.
When the request is forwarded to the third-party endpoint, the placeholder values are replaced with the respective payment credentials stored in the specified payment instrument or token.
When you set network_token.enabled to true, the Forward API checks if a network token is available for the instrument.
If a token is available and you also set request_cryptogram to true, the API also requests a new cryptogram.
The token values then become available to use as placeholders in your request body.
| Placeholder value | Description |
|---|---|
| The card verification value. This is also referred to as the card's security code. |
| The card's expiry month. |
| The card's expiry year. |
| The card's expiry year. |
| The full card number. |
| The first two digits of the card's PIN. |
| The cardholder's name as shown on the card. |
Information
If you use the Forward API to perform an authorization with a third party, you must handle any post-transaction actions directly with them. For example, captures, refunds, and disputes.
post
https://forward.checkout.com/forward
1{2"source": {3"type": "id",4"id": "src_wmlfc3zyhqzehihu7giusaaawu"5},6"reference": "ORD-5023-4E89",7"processing_channel_id": "pc_azsiyswl7bwe2ynjzujy7lcjca",8"destination_request": {9"url": "string",10"method": "POST",11"headers": {12"encrypted": "<JWE encrypted key-value object>",13"raw": {14"Idempotency-Key": "xe4fad12367dfgrds",15"Content-Type": "application/json"16}17},18"body": "{\"amount\": 1000,\"currency\": \"USD\",\"reference\": \"Test\",\"source\": {\"type\": \"card\",\"number\": \"{{card_number}}\",\"expiry_month\": \"{{expiry_month}}\",\"expiry_year\": \"{{expiry_year_yyyy}}\",\"name\": \"John Smith\"},\"payment_type\": \"Regular\",\"authorization_type\": \"Final\",\"capture\": true,\"processing_channel_id\": \"pc_xxxxxxxxxxx\",\"risk\": {\"enabled\": false},\"merchant_initiated\": true}"19}20}
1{2"request_id": "fwr_5fa7ee8c-f82d-4440-a6dc-e8c859b03235",3"destination_response": {4"status": 201,5"headers": {6"Cko-Request-Id": "5fa7ee8c-f82d-4440-a6dc-e8c859b03235",7"Content-Type": "application/json"8},9"body": "{ \n \"id\": \"pay_mbabizu24mvu3mela5njyhpit4\", \n \"action_id\": \"act_mbabizu24mvu3mela5njyhpit4\", \n \"amount\": 6540,\"currency\": \"USD\", \n \"approved\": true,\"status\": \"Authorized\", \n \"auth_code\": \"770687\", \n \"response_code\": \"10000\", \n \"response_summary\": \"Approved\", \n \"_links\": \n {\"self\": \n {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4\"}, \n \"action\": \n {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/actions\"}, \n \"void\": \n {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/voids\"}, \n \"capture\": \n {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/captures\"}\n}\n}"10}11}
If you receive a 200 response, the request was successfully forwarded to the specified third-party endpoint.
The response.status field specifies the response code returned by the third-party endpoint.
The response.body field contains the response body returned by the third-party endpoint, with any sensitive PCI information removed.
Note
Checkout.com cannot guarantee that the third-party processor will return a specific response to any requests you forward. If they are unresponsive, you must contact them directly to resolve the issue.
The fields forwarded to the third-party endpoint depend on the type of request:
If you set network_token.request_cryptogram to true and the network token and cryptogram are available, the following values are forwarded:
network_token_numbernetwork_token_expiry_monthnetwork_token_expiry_year_yyyy, ornetwork_token_expiry_year_yynetwork_token_typenetwork_token_cryptogramnetwork_token_eci
post
https://forward.checkout.com/forward
1{2"source": {3"type": "id",4"id": "src_5i3imssmshlu5apj2sgdozyht4"5},6"processing_channel_id": "pc_cvbbk7dyapdeho2qmuzozupapi",7"network_token": {8"enabled" : true,9"request_cryptogram": true10},11"destination_request": {12"url": "https://api.stripe.com/v1/payment_methods",13"request_method": "POST",14"headers": {15"raw": {16}17},18"body": "{ \n \"source\": \n {\"type\": \"network_token\", \n \"token\": \"{{network_token_number}}\", \n \"expiry_month\": \"{{network_token_expiry_month}}\", \n \"expiry_year\": \"{{network_token_expiry_year_yyyy}}\", \n \"token_type\": \"{{network_token_type}}\", \n \"cryptogram\": \"{{network_token_cryptogram}}\", \n \"eci\": \"{{network_token_eci}}\"}, \n \"amount\": 200, \n \"currency\": \"CHF\", \n \"capture\": true, \n \"processing_channel_id\" :\"pc_cvbbk7dyapdeho2qmuzozupapi\"}"19}20}
If you set network_token.request_cryptogram to false, the following values are forwarded:
network_token_numbernetwork_token_expiry_monthnetwork_token_expiry_year_yyyy, ornetwork_token_expiry_year_yynetwork_token_type
post
https://forward.checkout.com/forward
1{2"source": {3"type": "id",4"id": "src_5i3imssmshlu5apj2sgdozyht4"5},6"processing_channel_id": "pc_cvbbk7dyapdeho2qmuzozupapi",7"network_token": {8"enabled" : true,9"request_cryptogram": false10},11"destination_request": {12"url": "https://api.stripe.com/v1/payment_methods",13"request_method": "POST",14"headers": {15"raw": {16}17},18"body": "{ \n \"source\": { \n\"type\": \"network_token\", \n\"token\": \"{{network_token_number}}\", \n\"expiry_month\": \"{{network_token_expiry_month}}\", \n\"expiry_year\": \"{{network_token_expiry_year_yyyy}}\", \n\"token_type\": \"{{network_token_type}}\", \n\"previous_payment_id\": 1923712462419 \n}, \n\"amount\": 200, \n\"currency\": \"CHF\", \n\"capture\": true, \n \"processing_channel_id\" :\"pc_cvbbk7dyapdeho2qmuzozupapi\" \n}"19}20}
If you set body.source.is_network_token_available to true and the network token and cryptogram are available, the following values are forwarded:
network_token_numbernetwork_token_expiry_monthnetwork_token_expiry_year_yyyy, ornetwork_token_expiry_year_yynetwork_token_typenetwork_token_cryptogramnetwork_token_eci
If the network token or cryptogram are unavailable, the following card detail values are used as a fallback:
card_numberexpiry_monthexpiry_year_yyyy, orexpiry_year_yy
post
https://forward.checkout.com/forward
1{2"source": {3"type": "id",4"id": "src_5i3imssmshlu5apj2sgdozyht4"5},6"processing_channel_id": "pc_cvbbk7dyapdeho2qmuzozupapi",7"network_token": {8"enabled": true,9"request_cryptogram": true10},11"destination_request": {12"url": "https://api.stripe.com/v1/payment_methods",13"request_method": "POST",14"headers": {15"raw": {16"Idempotency-Key": "xe4fad12367dfgrds",17"Content-Type": "application/json"18}19},20"body": "{ \n \"source\": { \n \"is_network_token_available\": true, \n \"type\": \"network_token\", \n \"token\": \"{{network_token_number}}\", \n \"expiry_month\": \"{{network_token_expiry_month}}\", \n \"expiry_year\": \"{{network_token_expiry_year_yyyy}}\", \n \"cryptogram\": \"{{network_token_cryptogram}}\", \n \"eci\": \"{{network_token_eci}}\", \n \"billing_address\": { \n \"address_line1\": \"123 High St.\", \n \"address_line2\": \"Flat 456\", \n \"city\": \"London\", \n \"state\": \"GB\", \n \"zip\": \"SW1A 1AA\", \n \"country\": \"GB\" \n } } }"21}22}
To forward a payment request to Stripe, follow these steps:
- Create a payment method.
- Create a payment intent.
- Confirm the payment intent.
- Review the response.
If you're using the authorization header, we recommend you encrypt the value and provide it in the destination_request.headers.encrypted field in the request.
The Stripe API expects each key-value pair to be separated with an & character.
The Content-Type in the header must match the format of the content you send.
1curl --location 'https://forward.sandbox.checkout.com/forward' \2--header 'Content-Type: application/json' \3--header 'Authorization: YOUR_OAUTH_TOKEN' \4--data '{5"source": {6"type": "id",7"id": "src_u422hics5oouvix25ous63grcy"8},9"reference": "string",10"processing_channel_id": "pc_f2vtqcmhgykurkorrnnpz3kneq",11"destination_request": {12"url": "https://api.stripe.com/v1/payment_methods",13"method": "POST",14"headers": {15"encrypted": "",16"raw": {17"Content-Type": "application/x-www-form-urlencoded",18"Authorization": "Basic c2tfdGVzdF8yNlBIZW05QWhKWnZVNjIzRGZFMXg0c2Q6",19"Host":"api.stripe.com"20}21},22"body": "type=card&card[number]={{card_number}}&card[exp_month]={{card_expiry_month}}&card[exp_year]={{card_expiry_year_yyyy}}&card[cvc]=314"23}24}'
You receive a payment method ID, which you need to confirm the payment intent.
1curl --location 'https://forward.sandbox.checkout.com/forward' \2--header 'Content-Type: application/json' \3--header 'Authorization: YOUR_OAUTH_TOKEN' \4--data '{5"source": {6"type": "id",7"id": "src_u422hics5oouvix25ous63grcy"8},9"reference": "string",10"processing_channel_id": "pc_f2vtqcmhgykurkorrnnpz3kneq",11"destination_request": {12"url": "https://api.stripe.com/v1/payment_intents",13"method": "POST",14"headers": {15"encrypted": {16},17"raw": {18"Content-Type": "application/x-www-form-urlencoded",19"Authorization": "Basic c2tfdGVzdF8yNlBIZW05QWhKWnZVNjIzRGZFMXg0c2Q6",20"Host":"api.stripe.com"21}22},23"body": "amount=1000¤cy=usd&payment_method_types[]=card"24}25}'
You receive a payment intent ID, which you need to confirm the payment intent.
To confirm the payment intent, update the destination_request.url and destination_request.body fields with the payment method ID and payment intent ID.
1curl --location 'https://forward.sandbox.checkout.com/forward' \2--header 'Content-Type: application/json' \3--header 'Authorization: YOUR_OAUTH_TOKEN' \4--data '{5"source": {6"type": "id",7"id": "src_u422hics5oouvix25ous63grcy"8},9"reference": "string",10"processing_channel_id": "pc_f2vtqcmhgykurkorrnnpz3kneq",11"destination_request": {12"url": "https://api.stripe.com/v1/payment_intents/<STRIPE PAYMENT INTENT ID>/confirm",13"method": "POST",14"headers": {15"encrypted": {16},17"raw": {18"Content-Type": "application/x-www-form-urlencoded",19"Authorization": "Basic c2tfdGVzdF8yNlBIZW05QWhKWnZVNjIzRGZFMXg0c2Q6",20"Host":"api.stripe.com"21}22},23"body": "payment_method=<STRIPE PAYMENT METHOD ID>"24}25}'
1{2"request_id": "fwd_da32zq6rgymepl4sxiz3nnnicy",3"destination_response": {4"status": "ok",5"headers": {6"Server": [7"nginx"8],9"Date": [10"Fri, 21 Jun 2024 16:48:37 GMT"11],12"Connection": [13"keep-alive"14],15"Access-Control-Allow-Credentials": [16"true"17],18"Access-Control-Allow-Methods": [19"GET,HEAD,PUT,PATCH,POST,DELETE"20],21"Access-Control-Allow-Origin": [22"*"23],24"Access-Control-Expose-Headers": [25"Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required"26],27"Access-Control-Max-Age": [28"300"29],30"Cache-Control": [31"no-store, no-cache"32],33"Content-Security-Policy": [34"report-uri https://q.stripe.com/csp-report?p=v1%2Fpayment_methods; block-all-mixed-content; default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'"35],36"Cross-Origin-Opener-Policy-Report-Only": [37"same-origin; report-to=\"coop\""38],39"Idempotency-Key": [40"b7c44bf5-aa75-4fb3-9c6e-ad17a3e003c3"41],42"Original-Request": [43"req_UT51MBBX26MSzC"44],45"Report-To": [46"{\"group\":\"coop\",\"max_age\":8640,\"endpoints\":[{\"url\":\"https://q.stripe.com/coop-report?s=payins-bapi-srv\"}],\"include_subdomains\":true}"47],48"Reporting-Endpoints": [49"coop=\"https://q.stripe.com/coop-report?s=payins-bapi-srv\""50],51"Request-Id": [52"req_UT51MBBX26MSzC"53],54"Stripe-Should-Retry": [55"false"56],57"Stripe-Version": [58"2024-04-10"59],60"Vary": [61"Origin"62],63"X-Content-Type-Options": [64"nosniff"65],66"X-Stripe-Priority-Routing-Enabled": [67"true"68],69"X-Stripe-Routing-Context-Priority-Tier": [70"api-testmode"71],72"Strict-Transport-Security": [73"max-age=63072000; includeSubDomains; preload"74]75},76"body": "{\n \"id\": \"pm_1PUAdd2x6R10KRrhGCbuX0hq\",\n \"object\": \"payment_method\",\n \"allow_redisplay\": \"unspecified\",\n \"billing_details\": {\n \"address\": {\n \"city\": null,\n \"country\": null,\n \"line1\": null,\n \"line2\": null,\n \"postal_code\": null,\n \"state\": null\n },\n \"email\": null,\n \"name\": null,\n \"phone\": null\n },\n \"card\": {\n \"brand\": \"visa\",\n \"checks\": {\n \"address_line1_check\": null,\n \"address_postal_code_check\": null,\n \"cvc_check\": \"unchecked\"\n },\n \"country\": \"US\",\n \"display_brand\": \"visa\",\n \"exp_month\": 3,\n \"exp_year\": 2030,\n \"fingerprint\": \"NXzK7YAyyprPKex2\",\n \"funding\": \"credit\",\n \"generated_from\": null,\n \"last4\": \"1111\",\n \"networks\": {\n \"available\": [\n \"visa\"\n ],\n \"preferred\": null\n },\n \"three_d_secure_usage\": {\n \"supported\": true\n },\n \"wallet\": null\n },\n \"created\": 1718988517,\n \"customer\": null,\n \"livemode\": false,\n \"metadata\": {},\n \"type\": \"card\"\n}"77}78}
To forward a payment request to Adyen, follow these steps:
- Create a payment.
- Review the response.
The Adyen API expects a JSON payload, without any blank spaces between the key-value pairs. Provide the entire value in double quotes to ensure that single quotes are escaped correctly.
The Content-Type in the header must match the format of the content you send.
1{2"source": {3"type": "token",4"id": "tok_zjri4ogrqjuudnhsr7ooq5z6pq"5},6"reference": "string",7"processing_channel_id": "pc_f2vtqcmhgykurkorrnnpz3kneq",8"destination_request": {9"url": "https://checkout-test.adyen.com/v71/payments",10"method": "POST",11"headers": {12"raw": {13"Content-Type": "application/json",14"X-API-KEY": "<ADYEN API KEY>"15}16},17"body": "{\"amount\":{\"currency\":\"EUR\",\"value\":10},\"paymentMethod\":{\"type\":\"scheme\",\"encryptedCardNumber\":\"test_{{card_number}}\",\"encryptedExpiryMonth\":\"test_{{card_expiry_month}}\",\"encryptedExpiryYear\":\"test_{{card_expiry_year_yyyy}}\",\"encryptedSecurityCode\":\"test_737\"},\"reference\":\"my_reference\",\"merchantAccount\":\"PrizeTechnologyECOM\",\"returnUrl\":\"https://httpstat.us/\"}"18}19}
1{2"request_id": "fwd_jt72i7tsjfgergogie2qxzh7ei",3"destination_response": {4"status": "ok",5"headers": {6"traceparent": [7"00-22b8dcd266e756081fc1f50019293cdd-f151c37ad9b00661-01"8],9"Strict-Transport-Security": [10"max-age=31536000"11],12"X-Frame-Options": [13"SAMEORIGIN"14],15"X-Content-Type-Options": [16"nosniff"17],18"Set-Cookie": [19"JSESSIONID=ED43C7B0865E2210929050D36DA7EAE6.7d99355f-347b-18a0-fa83-70c08e69704f_0; Path=/checkout; Secure; HttpOnly"20],21"pspReference": [22"NPJ9LM2B88B26675"23],24"Transfer-Encoding": [25"chunked"26],27"Date": [28"Fri, 21 Jun 2024 16:10:38 GMT"29]30},31"body": "{\"additionalData\":{\"scaExemptionRequested\":\"transactionRiskAnalysis\"},\"pspReference\":\"QXBP9RM6Q327DN65\",\"resultCode\":\"Authorised\",\"amount\":{\"currency\":\"EUR\",\"value\":10},\"merchantReference\":\"my_reference\",\"paymentMethod\":{\"brand\":\"visa\",\"type\":\"scheme\"}}"32}33}
You can view the outcome of your forward requests in the Dashboard.
- Sign in to the Dashboard.
- Go to Vault > Credential forwarding.
On this page you can view:
- The total number of forward requests
- The response rate for your forward requests
- A breakdown of the responses received from the destinations you forwarded the requests to
- A history of all forward requests you've sent
Select a specific forward request to open its details page. On this page you can view:
- The forward request ID
- The date and time you forwarded the request
- Information about the destination you forwarded the request to – for example, the destination endpoint, the response code received, and the response time
- Information about the HTTP request sent and the HTTP response received
- Information about the stored credentials that you forwarded – for example, the payment instrument ID, card scheme, or issuing country