Forward stored credentials
Beta
Last updated: November 6, 2024
The Forward API enables you to enrich a payment request with raw payment credentials from a token or a payment instrument you've stored in our Vault. The request is then securely forwarded to your specified third-party API endpoint.
Information
To enable forwarding on your account, contact your Account Manager or [email protected].
This allows 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' \3--header 'Authorization: Bearer <OAUTH_TOKEN>'
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_
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 or 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.
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.
Placeholder value | Description |
---|---|
| The city of the billing address. |
| The country of the billing address. |
| The first line of the billing address. |
| The second line of the billing address. |
| The state of the billing address. |
| The ZIP code of the billing address. |
| 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": "\"{\"amount\": 1000, \"currency\": \"USD\", \"reference\": \"some_reference\", \"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}
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": "\"{\"id\": \"pay_mbabizu24mvu3mela5njyhpit4\", \"action_id\": \"act_mbabizu24mvu3mela5njyhpit4\", \"amount\": 6540, \"currency\": \"USD\", \"approved\": true, \"status\": \"Authorized\", \"auth_code\": \"770687\", \"response_code\": \"10000\", \"response_summary\": \"Approved\", \"_links\": {\"self\": {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4\"}, \"action\": {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/actions\"}, \"void\": {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/voids\"}, \"capture\": {\"href\": \"https://api.sandbox.checkout.com/payments/pay_mbabizu24mvu3mela5njyhpit4/captures\"}}}\""10}11}
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.
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}