This feature is not available on all Primer accounts. Contact your Customer Success Manager to receive access.
Proxy reference
Endpoint:POST https://proxy.primer.io/<psp-path>. The path after the host is forwarded to your PSP untouched, so use the same path you’d call on your PSP directly.
Headers:
Placeholders:
{{<token>.<FIELD>}} anywhere in the request body, regardless of how your PSP structures it. See the field table in Send the request through the proxy. A placeholder is never resolved outside the body. One in a header or in the URL path is left as-is and the request fails.
Every response carries X-Primer-Request-Id, whether it’s your PSP’s own response relayed untouched or a fault Primer raised. Give this ID to support when you need help tracing a request.
Limits and timeouts: request size and PSP response timeouts apply as with any proxied HTTP call; confirm current numeric limits with your Primer representative, as these are still being finalized.
Errors and retries
The proxy relays your PSP’s response byte for byte whenever your request reached the PSP: same status code, same body. A fault Primer raises instead carries anX-Primer-Proxy-Error header and a problem-details (application/problem+json) body with a type, title, status, detail, and the request ID. Use the presence of that header to tell a Primer error apart from your PSP’s own response.
An error can also come from in front of the proxy (rate limiting, a WAF block) before it reaches Primer’s own logic. Those carry no
X-Primer-Proxy-Error header and no request ID. If you need to trace one, ask support to look it up by timestamp and source IP instead.
Knowing whether it’s safe to retry:
- The error says the request wasn’t forwarded (
invalid-request,content-type-not-set,unauthorized,destination-not-allowed,token-not-found,token-consumed,token-expired, the422s, or apsp-unreachablebefore anything was sent): nothing reached your PSP. Safe to retry once you’ve fixed the underlying problem. - The outcome is unknown (a
psp-timeout, or apsp-unreachableafter the request may have left): your PSP may or may not have processed it. Don’t blindly retry. Check with your PSP first, using your own idempotency key if you set one on the PSP request, or query their API for the order. psp-response-too-largemeans your PSP did answer, but the response was over the proxy’s size limit and couldn’t be relayed to you. Check with your PSP for the outcome; don’t treat this as a failed payment.- The proxy never retries a request to your PSP itself. If you need retry behavior at your PSP, build it the same way you would calling that PSP directly, including reusing the PSP’s own idempotency key on a retried call so you don’t risk a duplicate charge.
Payment attempt states and decision window
A payment attempt moves through the following states:
Transitions:
REQUIRES_APPROVAL is the only state you can act from. approve, abort, and sending the token through the proxy are all only valid while the attempt is in this state. Once an attempt reaches a resolved, approved, aborted, or expired state, it’s terminal. A retry is a new payment attempt, created when the customer submits their details again.
The decision window is 15 minutes, from the moment the card is tokenized. It gives your backend time to run your own checks, call your PSP, and handle any 3D Secure challenge, before the attempt expires.
The token’s lifecycle: a token isn’t consumed by a proxy request itself. While the attempt is still in REQUIRES_APPROVAL, you can send the same token through the proxy more than once, for a 3DS challenge, a retry after a decline, or trying a second PSP of your own. The token is only consumed when you resolve the attempt, approve it (falling back to Primer), or it expires.
Limitations
What Primer Vault doesn’t support yet:- Mobile SDKs. The vault flow is web-only for now; iOS and Android support is planned but not available.
- Apple Pay and Google Pay. These wallets produce a device token and cryptogram instead of a card number, which the proxy doesn’t yet place into a PSP request.
- Network tokens. Charging a network token instead of the underlying PAN through the proxy isn’t supported yet.
- Primer 3DS on the vault. 3D Secure for a proxied payment has to run at your own PSP; Primer can’t authenticate the card on your behalf and hand you the result.
- Stored PSP credentials. You send your PSP credential on every proxy request, the same way you would calling the PSP directly; Primer doesn’t yet let you register it once and omit it from subsequent calls.
- PSPs that sign requests. A PSP that requires a signature over the whole request body, card data included (for example, dLocal), isn’t supported, since Primer fills the card fields in after you’ve built the request.
- Raw card data without the Primer checkout. Capturing a card yourself and handing it to Primer Vault directly, without going through the checkout, isn’t supported yet. Every card has to be tokenized through Primer’s own card form.
Troubleshooting
Nobody decided within the window, and the attempt expired. Check whether your backend actually received theprimer:payment-approval-required event and called one of approve, abort, or your PSP; a silent failure in that handler (a crash, an unhandled promise rejection) leaves the attempt waiting until it times out. Add logging around the handler if you can’t otherwise tell.
Your PSP processing failed, but you never called abort or resolve. The attempt stays open until the decision window closes, and the customer is left on a loading screen in the meantime. Always resolve the attempt (or abort it) from a finally-style path in your backend, even on an unexpected error, so the customer isn’t left waiting longer than necessary.
The customer reloaded the page mid-flow. Reload the checkout with the same client token. The SDK reads the current state of the attempt. If it’s still REQUIRES_APPROVAL, you’ll see the approval event fire again (deduplicate on paymentAttemptId); if it’s been resolved, you’ll see the result.
Your PSP charged the card, but the decision window had already expired by the time you tried to report it. Resolving an expired attempt fails, since the token and the attempt are both gone. The payment still happened at your PSP, so you need to reconcile it on your own side (refund it, or treat it as a successful out-of-band payment) rather than relying on Primer’s state. This is the main reason to keep your own PSP calls, including any 3DS challenge, comfortably inside the decision window.