| [ Web Proxy ] |
| Viewing: https://docs.stripe.com/payments/vault-and-forward | [Back] [Original] |
With Stripe Orchestration, Stripe manages the full processor integration on your behalfrouting, authentication, capture, refunds, and 3DS across multiple PSPs. Same PaymentIntents API, no PSP-specific code. Share your email address to request access.
Want access to Orchestration?
Enter your email to request access.
The Vault and Forward API allows you to tokenize and store card details in Stripes PCI-compliant vault and route that data to supported processors or endpoints. Use the API to:
To gain access to use Stripes forwarding service, contact Stripe support.
To collect card details, use the Payment Element to create a PaymentMethod. After you create a PaymentMethod, we automatically store card details in Stripes PCI compliant vault. If you have your own frontend, you can still use the Vault and Forward API by creating a PaymentMethod directly.
Typically, you can only reuse PaymentMethods by attaching them to a Customer. However, the Vault and Forward API accepts all PaymentMethod objects, including those not attached to a customer.
Similarly, the Vault and Forward API doesnt confirm or capture PaymentIntents. As a result, you might unintentionally use them to capture a payment on Stripe that was already captured on another processor.
The consumer payment credentials saved with Link transactions cant be transferred between payment processors. Any credentials saved through Link are excluded from forwarding.
CVCs expire automatically after a certain time period and also expire when used with the Vault and Forward API. If you require a CVC after either of these conditions are met, you must re-collect the card details.
If you use SetupIntents to collect card details before forwarding, card validation during SetupIntent confirmation can consume the CVC. When this happens, subsequent Forwarding API calls wont include the CVC, which can cause failures with processors that require it.
To access options for preserving CVC availability when using SetupIntents with the Forwarding API, contact Stripe support.
To send card details from Stripes vault, you must Create a ForwardingRequest and include the following parameters:
payment_method: The ID of the object containing the card details in Stripes vault. Accepted object types include: PaymentMethod (pm_), Source (src_) with an underlying card, Card (card_), and Issuing Card (ic_).url: The exact destination endpoint of your request.request.body: The API request body that you want to send to the destination endpoint (for example, the payments request you send to another processor). Leave any field where you normally input your customers card details blank.replacements: Fields that you want Stripe to substitute in the request.body. The available fields that we recommend always setting are card_number, card_expiry, card_cvc, and cardholder_name. For example, including card_number in the replacements array replaces the appropriate card number field for your destination endpoint in the request.body.The placeholder value for each card field in request.body must match the JSON type that the destination endpoint expects. Use "" for string fields and 0 for numeric fields. For example, if your destination endpoint requires expiryMonth and expiryYear as integers, set them to 0 instead of "":
"paymentMethod": {"number": "", "expiryMonth": 0, "expiryYear": 0, "cvc": "", "holderName": ""}
Stripe might be more lenient than other processors in validating the cardholder name field. If you use the cardholder_name replacements field, youre responsible for making sure that the names you use pass any validation enforced by the destination endpoint. For example, if the destination endpoint expects all names to only contain the letters A-Z with no accent marks or other writing systems, you must make sure the card details you forward meet this requirement. An alternative is to not use the cardholder_name replacements field and specify the cardholder name in your request body directly in your request.
You must format your request based on the data that the destination endpoint expects. In the example below, the destination endpoint expects an Idempotency-Key header and accepts a JSON body with the payment details.
We require you to pass API keys for the destination endpoint on each API request. Stripe forwards the request using the API keys you provide, and only retains hashed and encrypted versions of destination endpoint API keys.
curl https://api.stripe.com/v1/forwarding/requests \ -u "sk_test_wU7nrJCZspk1NPDxiQgAF05q:" \ -H "Idempotency-Key:" \ -d "payment_method={{IDEMPOTENCY_KEY}}" \ --data-urlencode "url=https://endpoint-url/v1/payments" \ -d "request[headers][0][name]=Destination-API-Key" \ -d "request[headers][0][value]={{DESTINATION_API_KEY}}" \ -d "request[headers][1][name]=Destination-Idempotency-Key" \ -d "request[headers][1][value]={{DESTINATION_IDEMPOTENCY_KEY}}" \ --data-urlencode "request[body]={\"amount\":{\"value\":1000,\"currency\":\"usd\"},\"paymentMethod\":{\"number\":\"\",\"expiryMonth\":\"\",\"expiryYear\":\"\",\"cvc\":\"\",\"holderName\":\"\"},\"reference\":\"{{REFERENCE_ID}}\"}" \ -d "replacements[0]=card_number" \ -d "replacements[1]=card_expiry" \ -d "replacements[2]=card_cvc" \ -d "replacements[3]=cardholder_name"{{PAYMENT_METHOD_ID}}
You can provide an Idempotency-Key to make sure that requests with the same key result in only one outbound request. Use a different and unique key for Stripe and any idempotency keys you provide on the underlying third-party request.
Use a new Idempotency-Key every time you make updates to request.body or request.header fields. Passing in the older idempotency key results in the API replaying older responses, including any previous validation errors or destination endpoint errors. We recommend that you use a new idempotency key when retrying requests that encountered an error reaching the destination endpoint to make sure the request is retried at the destination.
Use the Vault and Forward API to forward Apple Pay and Google Pay payment methods. Depending on the wallet and tokenization type, use different replacement fields so the wallet credentials forward correctly.
Stripe supports the following wallets:
To access wallet forwarding, contact Stripe support.
Link Payments currently unsupported for the Vault and Forward API. Link card transactions have a PaymentMethod object with a type of card and a wallet type of link. Dont include PaymentMethods in forwarding requests.
If your integration uses Link, route Link card transactions to Stripe for processing rather than forwarding them to a third-party endpoint.
To determine which replacement fields to use, fetch the PaymentMethod and check the wallet type and tokenization method:
The tokenization_type field indicates whether the payment method uses an FPAN or DPAN:
{ "id": "pm_1Q0PsIJvEtkwdCNYMSaVuRz6", "object": "payment_method", "type": "card", "card": { "wallet": { "type": "google_pay", "google_pay": { "tokenization_type": "dpan_or_ecommerce_token" // or "fpan" } } } }
The replacement fields you use depend on the wallet type:
card_number, card_expiry, card_cvc, cardholder_name)network_token_number, network_token_cryptogram, network_token_expiry, network_token_electronic_commerce_indicator)network_token_number, network_token_cryptogram, network_token_expiry, network_token_electronic_commerce_indicator)For Google Pay FPANs, use the same replacement fields as regular card payments:
curl https://api.stripe.com/v1/forwarding/requests \ -u "sk_test_wU7nrJCZspk1NPDxiQgAF05q:" \ -H "Idempotency-Key:" \ -d "payment_method={{IDEMPOTENCY_KEY}}" \ --data-urlencode "url=https://endpoint-url/v1/payments" \ -d "request[headers][0][name]=Destination-API-Key" \ -d "request[headers][0][value]={{DESTINATION_API_KEY}}" \ -d "request[headers][1][name]=Destination-Idempotency-Key" \ -d "request[headers][1][value]={{DESTINATION_IDEMPOTENCY_KEY}}" \ --data-urlencode "request[body]={\"amount\":{\"value\":1000,\"currency\":\"usd\"},\"paymentMethod\":{\"number\":\"\",\"expiryMonth\":\"\",\"expiryYear\":\"\",\"cvc\":\"\",\"holderName\":\"\"},\"reference\":\"{{REFERENCE_ID}}\"}" \ -d "replacements[0]=card_number" \ -d "replacements[1]=card_expiry" \ -d "replacements[2]=card_cvc" \ -d "replacements[3]=cardholder_name"{{PAYMENT_METHOD_ID}}
For both Google Pay and Apple Pay DPANs, use network token replacement fields:
curl https://api.stripe.com/v1/forwarding/requests \ -u "sk_test_4eC39HqLyjWDarjtT1zdp7dc:" \ -H "Idempotency-Key: {{IDEMPOTENCY_KEY}}" \ -d payment_method="{{PAYMENT_METHOD}}" \ --data-urlencode url="https://endpoint-url/v1/payments" \ -d "replacements[0]"=network_token_number \ -d "replacements[1]"=network_token_cryptogram \ -d "replacements[2]"=network_token_expiry \ -d "replacements[3]"=network_token_electronic_commerce_indicator \ --data-urlencode 'request[body]={"amount":{"value":1000,"currency":"usd"},"paymentMethod":{"networkToken":{"number":"","cryptogram":"","expiryMonth":"","expiryYear":"","electronicCommerceIndicator":""}},"reference":"{{REFERENCE_ID}}"}' \ -d "request[headers][0][name]"=Destination-API-Key \ -d "request[headers][0][value]"="{{DESTINATION_API_KEY}}" \ -d "request[headers][1][name]"=Destination-Idempotency-Key \ -d "request[headers][1][value]"="{{DESTINATION_IDEMPOTENCY_KEY}}"
Stripe makes a request to the destination endpoint on your behalf by inserting the card details from the PaymentMethod into the request.body. Where enabled and available, the Card Account Updater (CAU) automatically attempts to update and provide the latest available card details for requests.
Stripe then forwards the request to the destination endpoint. For example:
Stripe makes a POST request to the endpoint:
POST /v1/payments HTTP/1.1 User-Agent: Stripe Accept: */* Host: endpoint-url Content-Type: application/json Content-Length: 321
Stripe includes the following headers:
Destination-API-Key: {{DESTINATION_API_KEY}} Destination-Idempotency-Key: {{DESTINATION_IDEMPOTENCY_KEY}}
Stripe includes the following JSON body in the request:
{ amount: { value: 1000, currency: 'usd' }, paymentMethod: { number: '4242424242424242', expiryMonth: '03', expiryYear: '2030', cvc: '123', holderName: 'First Last', }, reference: '{{REFERENCE_ID}}' }
If youre using the Vault and the Forward API to make an authorization request, you must handle any post-transaction actions, such as refunds or disputes, directly with the third-party processor. Contact Stripe support if you require 3DS authentication across your multiprocessor setup.
When you use the Vault and Forward API to forward card details to a third-party processor, Stripe synchronously waits for a response from the destination endpoint. The timeout period for this response is less than a minute. Stripe redacts identified PCI-sensitive data, stores the redacted response from the destination endpoint, and returns a ForwardingRequest object, which contains data about the request and response.
When you use the Vault and Forward API to forward card details to a third-party processor, Stripe cant guarantee that the processor will provide any particular response to your forwarded API requests. If the third-party processor is unresponsive, you must reach out directly to that processor to resolve the issue.
{ "id": "fwdreq_123", "object": "forwarding.request", "payment_method": "{{PAYMENT_METHOD}}", "request_details": { "body": '{ "amount": { "value": 1000, "currency": "usd" }, "paymentMethod": { "number": "424242******4242", "expiryMonth": "03", "expiryYear": "2030", "cvc": "***", "holderName": "First Last" }, "reference": "{{REFERENCE_ID}}" }', "headers": [ { "name": "Content-Type", "value": "application/json" }, { "name": "Destination-API-Key", "value": "{{DESTINATION_API_KEY}}" }, { "name": "Destination-Idempotency-Key", "value": "{{DESTINATION_IDEMPOTENCY_KEY}}" }, ... ] }, "request_context": { "destination_duration": 234, "destination_ip_address": "35.190.113.80" }, "response_details": { "body": '{ // Response from the third-party endpoint goes here ... }', "headers": [ ... ], "status": 200 }, "replacements": [ "card_number", "card_expiry", "card_cvc", "cardholder_name" ] ... }
To set up your Vault and Forward API endpoint, you must:
Stripe supports forwarding API requests to the following endpoints:
icnow01.accertify.net/icNowImport/[path][prefix]-checkout-live.adyenpayments.com/checkout/v68/payments[prefix]-checkout-live.adyenpayments.com/checkout/v68/storedPaymentMethods[prefix]-checkout-live.adyenpayments.com/checkout/v69/payments[prefix]-checkout-live.adyenpayments.com/checkout/v69/storedPaymentMethods[prefix]-checkout-live.adyenpayments.com/checkout/v70/payments[prefix]-checkout-live.adyenpayments.com/checkout/v70/storedPaymentMethods[prefix]-checkout-live.adyenpayments.com/checkout/v71/payments[prefix]-checkout-live.adyenpayments.com/checkout/v71/storedPaymentMethods[prefix]-checkout-live.adyenpayments.com/checkout/v72/payments[prefix]-checkout-live.adyenpayments.com/checkout/v72/storedPaymentMethodsapi.basistheory.com/connections/stripe-forward/tokenizepayments.braintree-api.com/graphql[prefix].cardconnect.com/cardconnect/rest/authapi.checkout.com/tokensapi.checkout.com/payments[prefix].relay.evervault.appapi.ean.com/v3/itinerariesgateway.pmnts.io/v1.0/credit_cardsprod.api.firstdata.com/gateway/v2/paymentsapi.flexpay.io/v1/gateways/chargep01.mul-pay.jp/payment/ExecTran.jsonapi.paymentsos.com/tokensapi.pcivault.io/v1/capture/stripeapi.processout.com/cardsapi.rewardsnetwork.com/v2/members/enrollapi.rewardsnetwork.com/v2/members/*/cardsapi.shift4.com/chargesstbfep.sps-system.com/api/xmlapi.docore.spreedly.com/v1/payment_methods.json[prefix]/v1/clients/[ClientID]/accountstgapi.tokenex.com/Tokenize/Proxy/[ProfileID][prefix].live.verygoodproxy.com/cardsaccess.worldpay.com/api/paymentsaccess.worldpay.com/cardPayments/customerInitiatedTransactionsaccess.worldpay.com/tokenssecure.worldpay.com/jsp/merchant/xml/paymentServiceps.xsolla.com/forwarding/payments/cardapi-sandbox.y.uno/pci-stripe-forward-webhook/v1/forwardapi.y.uno/pci-stripe-forward-webhook/v1/forwardStripe supports HTTPS-based APIs that accept JSON/XML requests and return JSON/XML responses. If your destination endpoint isnt supported or you require a different API format, share the endpoint details with Stripe support to get support for your specific needs.
The Vault and Forward API can only forward requests to the following countries:
Additionally, ensure that your Stripe account is registered in one of these countries:
To access the Vault and Forward API, share the account IDs (acct_xxxx) for your test accounts with Stripe support.
Share the production details for destination endpoint with Stripe support. These include the following for destination endpoint: URL, HTTP method, documentation, fields, request headers, and encryption keys. Stripe then sets up destination endpoint for use with the Vault and Forward API in live mode.
To share third-party API keys, you must encrypt them by using the Stripe public key thats specific to the Vault and Forward API. Start by importing a public key using the GNU Privacy Guard (PGP). After you familiarize yourself with the basics of PGP, use the following PGP key to encrypt your third-party API keys:
To encrypt your third-party API keys with the Vault and Forward API PGP key:
Create a file named hash_encrypt_key.sh with the content below. The script generates a SHA256 hash of your API key, encrypts it with Stripes public key, and then Base64 encodes it.
To run the script, you must first install the sha256sum, gpg, and base64 utilities.
#!/bin/sh set -euo pipefail fail () { printf "Error: $1\n" >&2 && exit 1; } STRIPE_PUBLIC_KEY=AE863ADA1603150856C0A853A7B203177D034588 API_KEY=$(printf "$1" | tr -d '\n' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//') [ -x "$(command -v sha256sum)" ] || fail "sha256sum is not installed." [ -x "$(command -v gpg)" ] || fail "gpg is not installed." [ -x "$(command -v base64)" ] || fail "base64 is not installed." [ ! -z "$API_KEY" ] || fail "Please pass in an API key." grep -iqv "Basic \|Bearer " <<< "$API_KEY" || fail "Please omit the Basic/Bearer prefix." gpg --list-keys $STRIPE_PUBLIC_KEY > /dev/null 2>&1 || fail "Stripe public key not imported." printf "$API_KEY" | sha256sum | cut -d " " -f 1 | tr -d '\n' | gpg -e -r $STRIPE_PUBLIC_KEY --always-trust | base64 > encrypted_hashed_key.txt printf "Successfully generated encrypted_hashed_key.txt\n"
Run the script by passing your third-party API key in single quotes, omitting any Bearer or Basic prefix. The key must be the exact key that you use for actual requests to the destination endpoint, not including any prefix.
The script produces a file named encrypted_hashed_key.txt.
sh hash_encrypt_key.sh '<THIRD_PARTY_API_KEY>'
Use a restricted API key (RAK) to allow server-side access to only the Vault and Forward endpoints.
Authorization: Bearer <rk_...> credential when calling /v1/forwarding/requests from your server.Learn more about how to create a restricted API key.
To confirm that your integration works correctly with destination endpoint, initiate a ForwardingRequest using the PaymentMethod you created. This example uses pm_card_visa as a payment method.
curl https://api.stripe.com/v1/forwarding/requests \ -u "sk_test_wU7nrJCZspk1NPDxiQgAF05q:" \ -H "Idempotency-Key:" \ -d payment_method=pm_card_visa \ -d "url={{DESTINATION ENDPOINT}}" \ -d "request[headers][0][name]=Destination-API-Key" \ -d "request[headers][0][value]={{DESTINATION_API_KEY}}" \ -d "request[headers][1][name]=Destination-Idempotency-Key" \ -d "request[headers][1][value]={{DESTINATION_IDEMPOTENCY_KEY}}" \ --data-urlencode "request[body]={\"amount\":{\"value\":1000,\"currency\":\"usd\"},\"paymentMethod\":{\"number\":\"\",\"expiryMonth\":\"\",\"expiryYear\":\"\",\"cvc\":\"\",\"holderName\":\"\"},\"reference\":\"{{REFERENCE_ID}}\"}" \ -d "replacements[0]=card_number" \ -d "replacements[1]=card_expiry" \ -d "replacements[2]=card_cvc" \ -d "replacements[3]=cardholder_name"{{IDEMPOTENCY_KEY}}
The Vault and Forward API treats any response from the destination endpoint as a success and returns a 200, along with the destination endpoints response code in the response.body. For example, when the destination endpoint returns a status code of 400 to Stripe, the Vault and Forward API responds with a status code of 200. The response.body includes the destination endpoints 400 response and error message. Separately test the API request that you send to your destination endpoint to make sure that you dont have any errors.
You can view request logs and errors related to the Vault and Forward API in Workbench. Additionally, you can use the List API to fetch the logs from Stripe.
The request.headers and request.body in the incoming request are encrypted and appear as encrypted_request in the Dashboard.
| Web Proxy Viewer | New URL | Original Page |