Skip to content
Last updated

Standalone KYC

For the complete documentation index, see llms.txt. Append .md to any page URL for its markdown version.

Standalone KYC lets Banxa verify a customer's identity before they place an order. The customer completes verification in Banxa-hosted identity screens, which you show in an iframe or webview, or by redirecting the customer. Once the customer is verified, eligibility returns paymentReady: true and you take payment with Banxa Native, in your own UI.

Use Standalone KYC if you don't run your own KYC and don't want to build document, selfie, and liveness capture yourself.

Standalone KYC vs Quick start

In the Integration Guide's Quick start path, Banxa may route a user into a hosted WebView during checkout, after an order is created. Standalone KYC runs before any order, so the checkout itself stays fully native.


Before you start

  • Standalone KYC enabled for your account. Contact your Banxa integration manager. Until it's enabled, session requests return 403.

  • KYC webhooks enabled. The KYC webhook is how you learn the verification result. Ask your Banxa integration manager to confirm it's on for your account.

  • How you'll show the flow. Tell Banxa whether you'll use an iframe, a webview, or a redirect, so your account is set up to send the right completion signal.

  • Two sets of API credentials. Standalone KYC uses two Banxa APIs, so you need both:

    • your Native API HMAC key and secret, for eligibility and ramps
    • a Hosted Checkout API key, sent in the x-api-key header, for the session endpoint POST /{partnerRef}/v2/kyc/sessions. It's the same key and partner reference you initialise the Banxa payment SDKs with.

    If you don't have a Hosted Checkout API key, contact your Banxa integration manager.


How it works

BanxaYour backendYour appBanxaYour backendYour appCustomer enters email and country,then completes the identity stepsPOST /{partnerRef}/v2/kyc/sessions201 redirectUrl, expiresAtredirectUrlShow redirectUrl (iframe, webview, or redirect)banxa:kyc-complete message or redirect to returnUrlKYC webhook (kyc.status)POST /eapi/v0/identities/transactions/eligibilitypaymentReady: true
BanxaYour backendYour appBanxaYour backendYour appCustomer enters email and country,then completes the identity stepsPOST /{partnerRef}/v2/kyc/sessions201 redirectUrl, expiresAtredirectUrlShow redirectUrl (iframe, webview, or redirect)banxa:kyc-complete message or redirect to returnUrlKYC webhook (kyc.status)POST /eapi/v0/identities/transactions/eligibilitypaymentReady: true
  1. Your backend creates a session, passing the user's identityReference as externalCustomerId.
  2. Banxa returns a link and its expiry. The link is valid for 1 hour.
  3. You show the link to the customer.
  4. The customer enters their email and country (and an email one-time code, if that's enabled for your account). They then complete only the identity steps their verification level needs and that they haven't already completed.
  5. When nothing is left to collect, the customer sees "Your account is under review".
  6. Your app receives a completion signal. This means the customer finished, not that they passed.
  7. Banxa sends a KYC webhook when the result is known.
  8. Check eligibility. If paymentReady is true, continue with your payment method guide.

Use your identityReference as externalCustomerId

externalCustomerId and identityReference are the same identifier. Pass the user's identityReference as externalCustomerId, so the verification attaches to the identity you check eligibility against. The KYC webhook returns the same value as identity_reference.

If no identity exists yet for that identityReference, creating the session creates one.

The email the customer enters decides the identity

Banxa matches the customer by the email they enter in the hosted screens. If that email belongs to a different Banxa customer than the one your identityReference currently points to, your identityReference moves to that customer. Eligibility then reflects that customer, not the one you created earlier.

Make sure the customer uses the same email you used when you created the identity. If a customer you know is verified comes back as paymentReady: false, check whether they used a different email.


Create a session

This endpoint uses your Hosted Checkout API key, not HMAC. Create sessions from your backend, so the key never ships in your app or web page.

POST /{partnerRef}/v2/kyc/sessions
x-api-key: YOUR_HOSTED_CHECKOUT_API_KEY
Content-Type: application/json

{
  "externalCustomerId": "partner-abc123",
  "country": "AU",
  "tier": "standard",
  "returnUrl": "https://yourapp.com/kyc/done"
}
FieldRequiredDescription
externalCustomerIdYesYour identityReference for the user. Up to 255 characters. Longer values are rejected, not truncated.
countryNoThe customer's country of residence, as a 2-letter ISO 3166-1 code. The hosted screens still ask the customer for their country. Banxa saves a country only if the customer doesn't already have one, so whichever arrives first, yours or the customer's, is the one that's kept.
tierNostandard (default), enhanced, or express. See Verification levels.
returnUrlNoAn https URL or an app deep link, for example myapp://kyc-done. Where the customer goes when they finish. See Completion signals. If you leave it out, the default return URL set for your account in the Merchant Dashboard is used, if there is one.

Response 201

{
  "redirectUrl": "https://...",
  "expiresAt": "2026-08-21T08:10:00+00:00"
}

Repeat calls are safe. If you call again for the same externalCustomerId while the link is still valid, you get the same link and expiry back. A new tier takes effect the next time the customer loads a screen. A new country is only used if the customer doesn't have one yet. A new returnUrl only takes effect once the current link expires and you create a new one.

Errors

StatusMeaning
401Missing or invalid Hosted Checkout API key, or the key doesn't belong to {partnerRef}.
403Standalone KYC isn't enabled for your account.
422A field failed validation, for example an unsupported tier.
502Temporary upstream error. Retry with backoff.

See the API reference for the full schema.


Verification levels

You request a level with tier. Banxa combines it with the customer's country to decide exactly what to collect. Banxa's compliance team sets these requirements, and they can change.

  • standard (default): personal details, an ID document, and a selfie with a liveness check, plus any region-specific items such as a tax ID, purpose of transaction, or occupation.
  • enhanced: everything in standard, plus further items such as source of funds or proof of address, depending on the region.
  • express: personal details only, plus a tax ID in some regions. No ID document or selfie. Express must be enabled by Banxa for your account and for each country, and it isn't available in every country. If express isn't available, the customer gets standard and you don't receive an error. Banxa always falls back to more verification, never less.

If the customer's country isn't covered by a regional level, they get a catch-all level that asks for more than most regions. Customers in some regions may also be asked to complete a cooling-off period before their first order.

Whichever level you request, always rely on eligibility to decide whether a specific transaction can proceed.


Show the flow

How you show itWhat you doCompletion signal
iframeEmbed redirectUrl in an iframe with allow="camera; microphone".A postMessage to your page
WebviewLoad redirectUrl in a webview with camera and microphone access.Redirect to returnUrl
RedirectSend the browser to redirectUrl.Redirect to returnUrl

Banxa doesn't close the iframe or webview. Close it yourself after the completion signal.

The Banxa SDKs handle the webview, camera and microphone setup, and the completion signal for you.

Completion signals

iframe: Banxa posts these messages to your page with postMessage. These are the only messages the iframe sends.

typePayloadWhen
banxa:loading{ "type": "banxa:loading", "status": "loading" }The flow is loading
banxa:error{ "type": "banxa:error", "code": "...", "message": "..." }Something went wrong. code and message describe the error
banxa:kyc-complete{ "type": "banxa:kyc-complete", "status": "complete" }The customer reached the end of the flow

The banxa:kyc-complete payload is always the same. It never says whether the customer passed. Only accept messages whose event.origin matches the origin of redirectUrl. Banxa needs to enable embedded mode for your account and register your page's domain. Without embedded mode, the iframe sends no messages at all.

The Banxa SDKs report a few more events of their own, such as KYC errors and rejected messages. See your SDK reference.

Webview or redirect: when the customer finishes, they see the "Your account is under review" screen. If auto-redirect is enabled for your account, they're sent to returnUrl straight away. Otherwise, the screen shows a "Return to [your name]" button that takes them there. If you didn't send a returnUrl, your account's default return URL is used instead. With neither set, the customer stays on the under-review screen.


Get the result

The "under review" screen and the completion signal don't tell you the outcome. Use:

  1. The KYC webhook. Banxa sends it when the customer's verification status changes. It identifies the customer with identity_reference and carries kyc.status. See KYC webhooks.
  2. Eligibility. Before creating a ramp, call POST /eapi/v0/identities/transactions/eligibility with the same identityReference. Proceed only when paymentReady is true.
No status endpoint

At the moment there's no endpoint to query a Standalone KYC result, and no session status endpoint. Don't call GET /eapi/v0/identities/{identityReference} to get the status of a Standalone KYC verification. Use the KYC webhook and eligibility only.


Using the Banxa SDKs

The Banxa SDKs can show a Standalone KYC session and report when the customer finishes. Create the session on your backend and pass redirectUrl to your app, then use your SDK's KYC view:

The SDKs don't poll for a result. Their completion callback means the customer finished, not that they passed. Wait for the KYC webhook or check eligibility before creating an order.


Testing in sandbox

  • Use the sandbox base URL: https://api.banxa-sandbox.com/{partnerRef}/v2/kyc/sessions. In production, use https://api.banxa.com.
  • Use a new email address for each test customer. If you reuse an email, Banxa treats the session as that existing customer.
  • Test the document and selfie steps on a real device. Simulators don't provide a real camera.
  • If you use an iframe, check that you receive banxa:kyc-complete exactly once.

Troubleshooting

SymptomLikely causeWhat to do
401 when creating a sessionMissing or wrong x-api-key, or {partnerRef} doesn't match the account the key belongs toUse your Hosted Checkout API key (not your Native API HMAC credentials) and the matching partner reference
403 when creating a sessionStandalone KYC isn't enabled for your accountAsk your Banxa integration manager to enable it
422 when creating a sessionA field failed validation, for example an unsupported tier, or an externalCustomerId longer than 255 charactersFix the field named in the error response
The link has expiredLinks last 1 hourCreate a session again for the same externalCustomerId to get a new link. The customer isn't asked again for anything they've already completed
The camera doesn't work during the document or selfie stepThe iframe or webview has no camera or microphone accessiframe: add allow="camera; microphone". Webview or app: grant camera and microphone permissions. See your SDK reference
Nothing happens in your app when the customer finishesThe completion signal isn't set up for how you show the flowiframe: ask Banxa to enable embedded mode for your domain. Webview or redirect: send a returnUrl, and ask Banxa to enable auto-redirect so the customer doesn't have to tap Return
No KYC webhook arrivesKYC webhooks or your webhook URL aren't set up for your accountAsk your Banxa integration manager to enable KYC webhooks and confirm your webhook URL
Eligibility returns paymentReady: false right after the customer finishedCompletion only means the customer finished, not that they passedWait for the KYC webhook, then check eligibility again
You requested express, but the customer got the full document and selfie checkExpress isn't enabled for your account in the customer's country, or it isn't offered in that countryAsk your Banxa integration manager whether express can be enabled for that country. Otherwise this is expected: Banxa falls back to standard