The questions partners ask most often during integration, with links to the relevant guides.
Banxa has two credential types, and using the wrong one is the most common cause of 401 Unauthorized errors:
| Credential | Used for |
|---|---|
v2 API key (x-api-key header) | All /v2 endpoints: quotes, orders, payment methods, fiats, crypto, countries |
| HMAC key pair (API key + secret) | POST /v2/identities/token/share (KYC sharing), and verifying incoming webhook signatures |
Both credential sets are visible in the merchant dashboard, per environment. See Authentication & Environments.
Webhook signatures are verified with your HMAC secret, not your v2 x-api-key. If you only have a v2 key, retrieve the HMAC credentials from the merchant dashboard or contact your account manager. See Webhooks.
Check that you are calling the right environment. Sandbox keys only work against https://api.banxa-sandbox.com, production keys only against https://api.banxa.com. The base URL for each environment is shown in the merchant dashboard next to your API key.
Sandbox orders do not settle automatically in all cases and may require manual fulfilment by Banxa. No crypto moves on-chain in sandbox. If your order is stuck, contact your integration manager to progress it. See Testing Overview.
Sandbox pricing is not refreshed at production frequency. Use sandbox to validate the integration flow, not pricing accuracy. Production rates are live.
The KYC sharing API accepts requests in sandbox, but the sandbox environment is not connected to Sumsub. Test user profiles are verified manually by Banxa; ask your integration manager to verify each test user profile you create.
No. Sandbox validates mainnet address formats only. Use a valid mainnet-format address; no on-chain transaction occurs.
Sandbox is rate-limited to 120 requests per minute per merchant account. It is a shared testing environment, and the limit keeps it responsive for all merchants. If you hit 429s, reduce polling (use webhooks for order status instead) and add exponential backoff. Production has a higher limit; see Authentication & Environments.
Only the terminal statuses are final: complete, cancelled, declined, refunded. In particular, paymentReceived is not final: an order can still be cancelled after payment if it is held for risk or compliance review. Do not credit your customer or trigger downstream fulfilment until you receive complete. See Order Statuses.
Orders have two identifiers: a short numeric ID shown to the customer in the checkout and in emails, and a long hash used in API responses and webhook payloads. Always reconcile using the hash. See Order Lookup.
Webhooks are the real-time source of truth. The merchant dashboard order view can lag behind. Build your reconciliation on webhooks and the order lookup endpoint, not the dashboard.
The checkoutUrl returned by POST /v2/buy is valid for 1 minute, starting from Banxa's response to the order creation request. Once the URL has been loaded there is no further expiry. Create the order at the moment the customer confirms, then open the URL immediately. Do not create orders in advance.
The quote response shows processingFee and networkFee explicitly. The Banxa spread is embedded in the exchange rate, so for some payment methods processingFee can legitimately be 0 while the spread is applied via the rate. To calculate the effective all-in rate, divide the fiat amount by the crypto amount.
No. Quotes are indicative and carry no quote ID; there is nothing to pass into order creation. The final price is confirmed at checkout. Re-quote whenever the customer changes amount, currency, or payment method. See Get a Quote.
Yes, it is required on buy and sell orders. Use one stable identifier per customer, not per order. Reusing the same externalCustomerId is what lets returning verified customers skip repeat KYC. Generating a new ID per order breaks returning-customer recognition.
Once per customer. After sharing, pass the same externalCustomerId on every order for that customer. Calling it again for the same customer is safe and will not error. See KYC Sharing.
KYC sharing must be enabled on your account by Banxa, per environment, after a compliance review. If you see this error in sandbox or production, the feature has not yet been enabled for that environment. Contact your account manager. See Error Codes.
The most common cause is a name mismatch: the name on the payment instrument must match the name on the KYC profile. Mismatches route the order to manual review, which delays fulfilment.
Your embedding container must grant camera and microphone permissions. The fix depends on how you embed the checkout:
- Web (iframe): include
allow="camera; microphone"on the<iframe>element that loads the checkout. Without it, users see a "Failed to acquire camera" error during KYC. See iFrame Overview. - Mobile app (WebView): camera permissions must be granted at the app level. On Android, declare
CAMERAandRECORD_AUDIOin your manifest and grant permission requests in yourWebChromeClient. On iOS, implementWKUIDelegateto grant media capture requests, and note that KYC liveness requires iOS 15+ inWKWebView. Full configuration examples: Embedded Checkout Mobile.
If the desktop-to-phone QR handoff works but your in-app or in-page flow fails, missing container permissions are almost always the cause: the QR path opens the KYC step directly in the phone browser, outside your iframe or WebView.
One webhook URL per environment (one for sandbox, one for production), configured in the merchant dashboard.
They share the same configured URL but are separate notification types and may originate from different Banxa systems. Handle them independently by inspecting the payload. See Webhooks.
Final settlement can take from minutes to hours depending on payment method, blockchain confirmation times, and whether the order is held for review. If an order remains non-terminal for an extended period, check it via Order Lookup before escalating.
Still stuck? Contact your integration manager, or see the Error Codes reference.