Forward stored credentials
Beta
Last updated: April 2, 2025
The Forward API enables you to enrich a payment request with payment credentials you've stored in our Vault. You can enrich a payment with:
- The billing information stored within a payment instrument or token
- The card details stored within a payment instrument or token
- A network token's details
The request is then securely forwarded to your specified third-party API endpoint. For example, you can forward a request to external fraud engines, 3DS engines, and other payment service providers such as Stripe or Adyen.
Information
To enable forwarding on your account, contact your Account Manager or [email protected].
This enables you to:
- Store payment credentials in a single location and use them across multiple payment processors, 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.
Run the following command in your terminal to retrieve Checkout.com's JSON Web Key (JWK).
You'll need the JWK to encrypt sensitive request headers using JSON Web Encryption (JWE).
1curl --location 'https://forward.checkout.com/.well-known/jwks' \2--header 'Content-Type: application/json' \
Before you can create a forward request, you must have one of the following:
- A payment instrument you've created and stored in our Vault, with the prefix
src_
- A token you've generated, with the prefix
tok_
- A network token for a provisioned card
Information
Tokens expire after 15 minutes. If you want to reuse the payment credentials in future payments, you can create a payment instrument from a token.
Your forward request must include:
- The payment instrument, token, or network token to enrich the request with
- A public key – we recommend encrypting the public key if you use an API key
- An API key, or Access Key if you use OAuth 2.0 authentication
- The third-party endpoint to forward the request to, in the
destination_request.url
field - The HTTP method to use for the request, in the
destination_request.method
field - The JSON payload formatted according to the key-value pairs expected by the destination payment processor, in the
destination_request.body
field
Information
Checkout.com does not store the API keys you send in encrypted headers. We only use the keys to process the request in which they are provided.
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 logic that evaluates their availability and determines the appropriate fields to forward. You must set:
- the
network_token.enabled
field totrue
- the
network_token.request_cryptogram
field totrue
for customer-initiated transactions (CITs), orfalse
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 will be replaced with the respective payment credentials stored in the payment instrument or token you specified.
If an attempted network token is true, the Forward API verifies the availability of a network token when retrieving an instrument or creating an instrument from a token id. If a network token is present and generate_cryptogram is true
, it requests a new cryptogram. The network token values will be included as available variables, enabling their use in request template placeholders.
Placeholder value | Description |
---|---|
| The card's Card Verification Value (CVV). This is also referred to as the card's security code. |
| The card's expiry month, in the format |
| The card's expiry year, in the format |
| The card's expiry year, in the format |
| The full card number. |
| The cardholder name as shown on the card. |
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": {19"amount": 1000,20"currency": "USD",21"reference": "Test",22"source": {23"type": "card",24"number": "{{card_number}}",25"expiry_month": "{{expiry_month}}",26"expiry_year": "{{expiry_year_yyyy}}",27"name": "John Smith"28},29"payment_type": "Regular",30"authorization_type": "Final",31"capture": true,32"processing_channel_id": "pc_xxxxxxxxxxx",33"risk": {34"enabled": false35},36"merchant_initiated": true37}38}39}
If you receive a 200
response, the request was successfully forwarded to the third-party endpoint you specified.
The response's 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 sensitive PCI information removed.
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": {10"id": "pay_mbabizu24mvu3mela5njyhpit4",11"action_id": "act_mbabizu24mvu3mela5njyhpit4",12"amount": 6540,13"currency": "USD",14"approved": true,15"status": "Authorized",16"auth_code": "770687",17"response_code": "10000",18"response_summary": "Approved",19"_links": {20"self": {21"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4"22},23"action": {24"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/actions"25},26"void": {27"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/voids"28},29"capture": {30"href": "https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/captures"31}32}33}34}35}
Information
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.
When you forward stored credentials, the following scenarios determine which fields are forwarded to the third-party endpoint:
The fields forwarded to the third-party endpoint are determined by 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_number
network_token_expiry_month
network_token_expiry_year_yyyy
, ornetwork_token_expiry_year_yy
network_token_type
network_token_cryptogram
network_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": {19"source": {20"type": "network_token",21"token": "{{network_token_number}}",22"expiry_month": "{{network_token_expiry_month}}",23"expiry_year": "{{network_token_expiry_year_yyyy}}",24"token_type": "{{network_token_type}}",25"cryptogram": "{{network_token_cryptogram}}",26"eci": "{{network_token_eci}}"27},28"amount": 200,29"currency": "CHF",30"capture": true,31"processing_channel_id" :"pc_cvbbk7dyapdeho2qmuzozupapi"32}33}34}
If you set network_token.request_cryptogram
to false
, the following values are forwarded:
network_token_number
network_token_expiry_month
network_token_expiry_year_yyyy
, ornetwork_token_expiry_year_yy
network_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": {19"source": {20"type": "network_token",21"token": "{{network_token_number}}",22"expiry_month": "{{network_token_expiry_month}}",23"expiry_year": "{{network_token_expiry_year_yyyy}}",24"token_type": "{{network_token_type}}",25"previous_payment_id": 192371246241926},27"amount": 200,28"currency": "CHF",29"capture": true,30"processing_channel_id" :"pc_cvbbk7dyapdeho2qmuzozupapi"31}32}33}
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_number
network_token_expiry_month
network_token_expiry_year_yyyy
, ornetwork_token_expiry_year_yy
network_token_type
network_token_cryptogram
network_token_eci
If the network token or cryptogram are unavailable, the following card detail values are used as a fallback:
card_number
expiry_month
expiry_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": {21"source": {22"is_network_token_available": true,23"type": "network_token",24"token": "{{network_token_number}}",25"expiry_month": "{{network_token_expiry_month}}",26"expiry_year": "{{network_token_expiry_year_yyyy}}",27"cryptogram": "{{network_token_cryptogram}}",28"eci": "{{network_token_eci}}",29"billing_address": {30"address_line1": "123 High St.",31"address_line2": "Flat 456",32"city": "London",33"state": "GB",34"zip": "SW1A 1AA",35"country": "GB"36}37}38}39}40}
To forward a payment request to Stripe, you must:
- Create a payment method.
- Create a payment intent.
- Confirm the payment intent.
- Review the response.
If you are using the authorization header, we recommend you encrypt the value and use 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 should 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}'
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}'
To confirm the payment intent, update the destination_request.url
and destination_request.body
fields with the payment intent and payment method IDs returned in the previous steps.
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, you must:
- Create a payment.
- Review the response.
The Adyen API expects a JSON payload, without any blank spaces between the key-value pairs. The entire value should be wrapped in double quotes to ensure that single quotes are escaped correctly.
The Content-Type
in the header should 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}