Auth Tokens
Every token type the retail API issues or accepts, what each one unlocks, and how long it lives.
Before You Start
Read the following guides before proceeding:
| Guide | Why |
|---|---|
| Getting Started | Platform overview and setup |
| Api Basics | Required headers and request configuration |
| Authentication | How each token is obtained, with code |
Overview
The retail API uses more than one kind of token, and they are not interchangeable. This page is the
inventory: what each one is, what it unlocks, and how long it lasts. Authentication
is where the flows and code live.
| Token | Obtained from | Proves | Unlocks | Lifetime |
|---|---|---|---|---|
| S2S token | POST /api/v1/token (client credentials) | Your company's identity | Every endpoint, with X-User-* headers naming the user | 48 hours |
| User token | POST /api/v1/user/authorize | One specific user | The same endpoints, scoped to that user — no identity headers needed | Read expires_at |
| Identity token | Privy or Crossmint, in your front end | The end user's sign-in | Exchange for a Wirex token — it is not a Wirex credential itself | Set by the provider |
| Action token | POST /api/v1/confirmation/signature/verify or POST /api/v1/confirmation/sms/verify | A fresh, deliberate confirmation by the user | One action type only — card details, 3DS, or phone verification | 5 minutes |
| KYC SDK token | POST /api/v1/user/verification-token | Nothing on its own | Embedding the SumSub SDK in your app | Set by SumSub |
| SumSub share token | You generate it at SumSub | That your SumSub applicant may be shared with Wirex | Registering a user with verification you already hold | Set by SumSub |
Only the first two go in the Authorization header. The rest are inputs to a specific call.
Which One Do I Need?
| You want to | Use |
|---|---|
| Call any endpoint from your backend | S2S token + X-User-Wallet / X-Chain-Id |
| Let a client app call Wirex directly, without your credentials | User token |
| Sign users in with Privy or Crossmint | Identity token, exchanged for a Wirex token |
| Read a PAN, CVV or PIN | S2S or user token plus an action token |
| Approve a 3DS challenge in-app | S2S or user token plus an action token |
| Confirm a phone number | S2S or user token plus an action token |
| Run KYC inside your own app | KYC SDK token |
| Onboard a user you have already verified at SumSub | SumSub share token |
Bearer Tokens
S2S Token
Client-credentials token representing your company, not any user. HMAC-SHA256, scope partner:full,
48-hour validity. Because it carries no user, most endpoints require X-User-Wallet and X-Chain-Id
headers to name the user the request is for.
Cache it until shortly before exp and refresh with a margin. POST /api/v1/token is rate-limited
per IP and per client — back off exponentially on 429.
User Token
Issued from an S2S token plus identity headers, and scoped to that one user. Its purpose is to be
handed to a client application so the client can call Wirex directly without ever seeing your
client_secret.
A user token identifies its user, so identity headers are not needed on requests that carry it.
Which of the Two
| S2S token | User token | |
|---|---|---|
| Represents | Your company | One user |
| Lives on | Your backend only | Safe to pass to a client app |
| Identity headers | Required on user-scoped endpoints | Not needed |
| Blast radius if leaked | Every user in your company | One user |
Naming across trees. The Corporate API calls its client-credentials token the partner token,
and its second-leg scoped token the corporation token. Same two-step shape, different names —
see Corporate Authentication.
Action Tokens
Bearer tokens authenticate the caller. Action tokens prove the user just deliberately confirmed a
specific thing, and are required on top of a bearer token for sensitive operations.
An action token is minted for one action_type and is rejected by any operation belonging to another.
Action Types
action_type | Confirms | Obtainable by signature | Obtainable by SMS |
|---|---|---|---|
GetCardDetails | Reading PAN, CVV and PIN | Yes | Yes |
3dsChallenge | Approving or declining a 3DS challenge | Yes | No |
VerifyPhone | Confirming a phone number | Yes | Yes |
Values are matched case-insensitively, but send them exactly as written above. An unrecognised value
fails with action_type: Invalid value for action type and issue: invalid_value.
3dsChallenge cannot be obtained through SMS. POST /api/v1/confirmation/sms rejects it with the
same invalid_value error as an unknown type — the signature route is the only way to mint it.
Obtaining One by Signature
POST /api/v1/confirmation/signature/verify
The user signs this exact message with the wallet's private key:
By signing this I confirm that I am executing action {action_type} at {nonce}
| Field | Type | Required | Description |
|---|---|---|---|
action_type | string | Yes | The action being confirmed |
message_signature | string | Yes | Signature over the message above |
nonce | integer | Yes | Unix timestamp used when forming the message |
public_key | string | No | Hex-encoded public key of the signer. Required on XRPL, where the address cannot be derived from the signature; ignored elsewhere |
The nonce must be no more than 5 minutes old. An older timestamp is refused, so form the message
at signing time rather than reusing a value from earlier in the session.
Obtaining One by SMS
POST /api/v1/confirmation/sms
POST /api/v1/confirmation/sms/verify
The first call sends a code and returns a session; the second exchanges the code for the action token.
See Card Details for the full flow.
Validity
An action token is valid for 5 minutes and for one action type. The failures are distinct:
| Error | error_details | Meaning |
|---|---|---|
ErrorExpired | action_token: expired | More than 5 minutes old — mint a new one |
ErrorInvalidField | action_token: invalid_purpose | Minted for a different action_type |
ErrorInvalidField | action_token: invalid_token | Malformed |
ErrorInvalidField | action_token: invalid_claims | Claims could not be parsed |
invalid_purpose is the one that catches integrations out: it is not an expiry and retrying does not
help. Mint a token for the action you are actually performing.
KYC Tokens
These are SumSub credentials, not Wirex ones. They appear here because they are easy to confuse with
the tokens above.
| Token | Direction | Purpose |
|---|---|---|
| KYC SDK token | Wirex → you (POST /api/v1/user/verification-token) | Embed the SumSub SDK in your own app |
| Verification link | Wirex → you (POST /api/v1/user/verification-link) | Redirect the user to the hosted SumSub widget |
| SumSub share token | You → Wirex (sharing_data.sharing_token on registration) | Reuse verification you already hold, instead of re-verifying |
The share token runs opposite to every other token on this page — you generate it at SumSub and
send it to Wirex. See Shared KYC.
Handling
- Store
client_secretin a secrets manager. Never in source control, never in client-side code - Cache the S2S token until shortly before
exp; refresh with a margin - A user token is that user's credential — scope it and expire it like one
- Never log a full token; truncate for debugging
- Use HTTPS with TLS 1.2 or later and validate certificates
- Do not mint action tokens speculatively. They last 5 minutes and are tied to one action
Updated 20 days ago

