Skip to content
Last updated

Every Banxa Native transaction is tied to an identityReference — your stable identifier for the user. Banxa accumulates KYC state, verification history, and compliance tier against it, so a user who verifies once doesn't need to verify again.

Banxa's underlying record key is email. When Banxa receives an email on any identityReference — via identity creation, OTP verification, or a PATCH — it links the two. If that email already exists on another identity, the records merge automatically: the newer identityReference inherits the older account's KYC history. Getting the user's email into Banxa early is what determines whether a returning user is recognised correctly.


Requirements

An identityReference must be:

  • Unique per user. Two users must never share an identityReference.
  • Opaque. Do not include PII (name, email, phone number) in the value itself.

The format is up to you — use whatever you can derive consistently and uniquely for the same person.


When to create the identity

Create the identity as early as possible — ideally before pricing. Pricing doesn't strictly require it, but Banxa distinguishes between new and returning customers, so pricing is most accurate when Banxa already knows the user. Eligibility requires knowledge of the user, so either create the identity before calling eligibility, or call eligibility with the user's email and country directly.


Which approach applies to you

The key question is whether your system already stores a unique identifier per user.

Approach 1Approach 2
When to useYou store a unique ID per userYou have no stored per-user ID
Typical integrationExchanges, custodial walletsNon-custodial wallets
Works across multiple walletsYesYes, with OTP
KYC history persists if wallet changesYesYes, with OTP
Merging requiredNoYes, via email + OTP

Approach 1 — You have a stored per-user ID

If your system already has a stable identifier for each user — a database ID, a UUID, a hashed account reference — use that as your identityReference. The choice of what to store is yours; a common pattern is to hash the internal ID to keep the value opaque.

This is the simplest approach: your identifier is already stable and independent of wallet addresses or email changes. KYC history accumulates against one record across all the user's devices and wallets.


Approach 2 — You have no stored per-user ID

If your app has no concept of a persistent user — common for non-custodial wallets, apps using device fingerprints, or session-based flows — you need to derive an identityReference at transaction time. A common pattern is to hash the wallet address, but any value that is unique per person works.

Email is required before a transaction at all times. Without it, Banxa cannot recognise a returning user who comes back with a different identityReference — eligibility returns results as if they are a new user, causing transaction failures or unnecessary KYC friction.

Linking email to the identity

Email can be provided to Banxa at any of these points — choose what fits your flow:

  • At identity creation — include email in POST /eapi/v0/identities/basic
  • Via OTP verification — create a sparse identity first, then bind the email via POST /eapi/v1/verifications/otp (recommended — see below)
  • At Sumsub token sharing — include email in POST /eapi/v0/identities/share/token; this also lets you discover upfront whether KYC token sharing or just a basic identity is needed

Handling new and returning users

There is no single required flow — the right approach depends on your app's architecture. The variants below cover every meaningful combination. Pick the one that fits.


New users

Create identity with email, then eligibility

The most common pattern for apps with their own authentication. Include email at creation, then proceed to eligibility. If a Banxa record already exists for that email, creation returns 422 with code 81 — retrieve the existing record via GET and continue as a returning user.

201 — new record

422 code 81 — email exists

User initiates transaction

POST /identities/basic
identityReference + email

Response

POST /eligibility
with identityReference

GET /identities/any-ref?email=email
Returns real identityReference

Proceed to payment

201 — new record

422 code 81 — email exists

User initiates transaction

POST /identities/basic
identityReference + email

Response

POST /eligibility
with identityReference

GET /identities/any-ref?email=email
Returns real identityReference

Proceed to payment


Eligibility first, then create identity

Call eligibility with email and country before creating the identity. The response tells you upfront whether KYC token sharing (SELFIE/DOCUMENT requirements) or just basic structured fields are needed — avoiding an extra round-trip after creation.

User initiates transaction

POST /eligibility
email + countryOfResidence only

Note requirements returned

POST /identities/basic
identityReference + email

Handle requirements from step 1
token sharing and/or PATCH

POST /eligibility
with identityReference

Proceed to payment

User initiates transaction

POST /eligibility
email + countryOfResidence only

Note requirements returned

POST /identities/basic
identityReference + email

Handle requirements from step 1
token sharing and/or PATCH

POST /eligibility
with identityReference

Proceed to payment

Eligibility called with email + country returns paymentReady and requirements only — no identityReference is returned. The identityReference is yours to define.


Sparse identity + OTP

Required if your app has no authentication mechanism of its own. Create the identity without an email first, then bind the email via OTP. OTP verifies the user owns the address and triggers merging if that email already exists on another Banxa identity.

User initiates transaction

POST /identities/basic
identityReference only

Collect email from user in your UX

POST /verifications/otp
identityReference + email → OTP sent

User enters OTP code

POST /verifications/otp/verify
Email bound — merge triggered if email already on another record

POST /eligibility

Proceed to payment

User initiates transaction

POST /identities/basic
identityReference only

Collect email from user in your UX

POST /verifications/otp
identityReference + email → OTP sent

User enters OTP code

POST /verifications/otp/verify
Email bound — merge triggered if email already on another record

POST /eligibility

Proceed to payment

See OTP Email Verification for the endpoint reference.


Sumsub token sharing at onboarding

If your platform runs Sumsub KYC when users sign up, share the verification token with Banxa at that point — not at transaction time. The user arrives at their first transaction already verified.

User completes KYC
at onboarding

POST /identities/share/token
identityReference + email + Sumsub token

Poll GET /identities/{ref}
or receive KYC webhook
until kyc.status = VERIFIED

Transaction time:
POST /eligibility → likely paymentReady: true

User completes KYC
at onboarding

POST /identities/share/token
identityReference + email + Sumsub token

Poll GET /identities/{ref}
or receive KYC webhook
until kyc.status = VERIFIED

Transaction time:
POST /eligibility → likely paymentReady: true

See KYC Token Sharing for the full flow.


Returning users

identityReference stored

If you saved the identityReference from a previous session, call eligibility directly with the stored value. Transaction context may have changed since the last visit — re-check eligibility each time.

POST /eapi/v0/identities/transactions/eligibility
{ "identityReference": "stored-ref", ... }

identityReference not stored — GET lookup by email

The user returns on a different device or with a different wallet address and you have no stored reference. Pass any value in the path and include the user's email as a query parameter — Banxa resolves to the identityReference linked to that email.

GET /eapi/v0/identities/[email protected]
{
  "identityReference": "abc123",
  "account": {
    "exists": true,
    "blocked": false,
    "createdAt": "2026-05-25T00:34:03Z"
  },
  "kyc": {
    "status": "VERIFIED"
  }
}

Use the identityReference returned here for all subsequent calls. Email is an optional query parameter — if omitted, Banxa uses the path value as-is.


Can't distinguish first-time vs returning users upfront

If you can't tell whether a user is new or returning before calling the API, attempt creation and branch on the response.

201 — genuinely new

422 code 81 — record exists

User initiates transaction

POST /identities/basic
new identityReference + email

Response

Proceed as new user
POST /eligibility

GET /identities/any-ref?email=email
Retrieve real identityReference

Proceed to payment

201 — genuinely new

422 code 81 — record exists

User initiates transaction

POST /identities/basic
new identityReference + email

Response

Proceed as new user
POST /eligibility

GET /identities/any-ref?email=email
Retrieve real identityReference

Proceed to payment


No stored reference and no email available

Design to avoid this state

Always collect email before checking eligibility. Without it, Banxa treats the user as new, which causes two problems:

  • Unnecessary re-KYC — the user faces requirements they have already satisfied on a previous account.
  • Wrong eligibility tier — prior transaction history qualifies users for more favourable compliance tiers. Without the email, Banxa has no way to know. Once email is eventually linked, the requirements change — creating friction mid-flow.

Providing email and record merging

Merging occurs whenever Banxa receives an email — at identity creation, via OTP, via Sumsub token sharing, or via a PATCH. The identityReference the email arrives on inherits all prior KYC history, and this chains: a user can return with a different identityReference multiple times without losing verification history.

OTP and authentication:

Your app has its own authenticationOTP
YesOptional — your login acts as the email verification step
NoRequired — the only way to verify the user owns the address

OTP is configured before launch — contact your Banxa integration manager to confirm the setup. See OTP Email Verification for the endpoint reference and flow.