This feature is not available on all Primer accounts. Contact your Customer Success Manager to receive access. See Get started for one-time setup.
Create the client session
Create a client session with the vault’s approval mode and acustomerId:
The decision window
Once the customer submits their card, your backend has 15 minutes to either approve the attempt or report an outcome from your own PSP, covering your own checks, the PSP request, and any 3D Secure challenge at your PSP. See Payment attempt states and decision window for what happens if you miss it.Show the checkout and capture the card
Render the checkout with the client token from the session:primer:payment-approval-required:
paymentMethodToken carries the token your backend uses next, plus the data it needs to decide where the payment goes. See Decide where the payment goes below.
Decide where the payment goes
Your backend receives, from the approval event, the payment method token and the card’s BIN data: card network, first digits, last four digits, and issuer. If you only use the vault and have no Primer processing connected, the decision is made for you. Take the token and go to the proxy. If you’ve also connected a processor in Primer, you choose per payment, for example by card network, issuer country, or any rule you already run:approve on the attempt. Primer creates the payment and manages the rest of the lifecycle, including 3DS and retries.
approve needs the transactions:authorize scope. If the decision window has expired, approve returns 410 PaymentAttemptExpired and the attempt can no longer be acted on; the customer has to submit a new payment.
Route to your own PSP: take paymentMethodToken.token and send your usual PSP request through the proxy, then report the outcome.
Stop the payment: call abort if you decide not to proceed at all, for example because your own fraud check failed before you’ve even tried a PSP.
abort for a decision made before you’ve sent anything to a PSP; if your own PSP processing fails after you’ve already tried it, that’s a fallback to Primer or a reported failure, not an abort.
Only card payments can route to the proxy. Alternative payment methods always go through Primer orchestration, so mixing card and non-card payment methods in the same checkout needs no extra integration work.
Send the request through the proxy
Send the same request you’d normally send to your PSP, but to the proxy, with the card fields replaced by placeholders referencing the token:
Replace card fields in the request body with
{{<token>.<FIELD>}} placeholders:
Placeholders work regardless of how your PSP structures its request body. They’re only resolved in the request body; a placeholder in a header or in the URL path is never substituted and the request fails. A placeholder that’s malformed, references an unknown field, or references a field not available on that token (such as
CVV on a saved token) fails the whole request rather than being silently dropped.
Stripe example (form-encoded):
X-Primer-Proxy-Error header and a problem-details body instead of a PSP response. See Errors and retries.
Handle 3DS at your PSP
3D Secure, when it’s needed, runs at your own PSP. Primer doesn’t run 3DS on a proxied payment.- In-page challenge: your PSP’s response tells you a challenge is required; render it in your page using your PSP’s SDK, exactly as you do today. The customer completes it without leaving your checkout.
- Redirect challenge: the customer is sent to the issuer’s page and back. Your return URL should land them back on your checkout with the same client session.
Report the outcome
Once you have a result from your PSP, resolve the attempt so the checkout can show it:resolve needs the payment_instrument:write scope. It’s idempotent on paymentAttemptId: a retried call with the same body returns the original response instead of failing, so you can safely retry after a timeout without risking a duplicate. See Errors and retries for the full error catalogue, including what happens if you resolve after the window has expired.
Once the outcome is reported, call continueFlow() from your frontend. The checkout listens for the result and shows a success or failure screen:
primer:payment-success and onPaymentSuccess always carry a Primer payment object and don’t fire for a proxied payment. Listen for primer:payment-success-external instead if your integration handles success itself.
Fall back to Primer
If you send a card through the proxy and your own PSP declines or fails, the token is still usable, since the attempt is still open. You can retry with a different PSP of your own, or fall back by callingapprove on the same attempt, so Primer processes the same card instead of you reporting FAILED: