Portal — Identity & Session
- Base path
/api/portal/v1/wallet/auth- Identity
register,login,otp/verify,otp/resend,password/reset*are opened by the publishable key (rate limited per IP). Past that pointsession,sessions,devices,logoutrequire a customer session.- Authorization
- The session itself is the authorization; a user reaches only their own record.Step-up: for money-out actions the session alone is not enough; an OTP code or a trusted action token is required.
- Cross-surface
- This surface is for the end user; your merchant server does not call it. For the server-side counterpart see the s2s API.
An end-user session is established in three stages: identification (publishable key) → identity (register/login) → verification (OTP). Sensitive operations add step-up on top.
All endpoints live under /api/portal/v1/wallet/auth/*.
Registration
POST /api/portal/v1/wallet/auth/register| Field | Type | Required | Description |
|---|---|---|---|
phone | string | ✅ | Phone number — the wallet's deduplication key |
password | string | ✅ | |
email | string | — | |
programId | string | — | When you run several programs |
consentCodes | string[] | — | Agreement codes the user accepted |
device | object | — | Device descriptor (below) |
threatPayload | object | — | Device risk signals |
Device object:
| Field | Description |
|---|---|
fingerprintHash | Device fingerprint |
platform | OS/platform |
installId | Install identifier |
deviceName | Name shown to the user |
The phone number is the wallet's identity. Binding a wallet to an unverified number means handing it to whoever takes over that number — which is why registration does not complete without OTP verification.
Login
POST /api/portal/v1/wallet/auth/loginphone + password (plus optional programId, device, threatPayload). The response returns an OTP challenge (challengeId).
OTP verification
POST /api/portal/v1/wallet/auth/otp/verify # { challengeId, code, programId?, device? }
POST /api/portal/v1/wallet/auth/otp/resend # { challengeId, programId? }On success the session opens: access + refresh tokens.
Expose otp/resend behind a countdown. Apps that restart the whole login instead of resending put users into an unnecessary loop.
Session management
POST /api/portal/v1/wallet/auth/refresh # { refreshToken? }
POST /api/portal/v1/wallet/auth/logout
GET /api/portal/v1/wallet/auth/session # current session
GET /api/portal/v1/wallet/auth/sessions # all active sessions
DELETE /api/portal/v1/wallet/auth/sessions/{sessionId}GET /api/portal/v1/wallet/auth/sessions and DELETE /api/portal/v1/wallet/auth/sessions/{id} power the user's "sign out other devices" screen. Put it in settings — in wallet apps it is an expected capability.
Device management
GET /api/portal/v1/wallet/auth/devices
PATCH /api/portal/v1/wallet/auth/devices/{deviceId} # { deviceName }
DELETE /api/portal/v1/wallet/auth/devices/{deviceId}Users can name and remove devices. Removing a device ends its session.
Password operations
POST /api/portal/v1/wallet/auth/password/change # { currentPassword, newPassword }
POST /api/portal/v1/wallet/auth/password/reset # { phone, programId? } → challengeId
POST /api/portal/v1/wallet/auth/password/reset/complete # { challengeId, code, newPassword, programId? }Password reset is OTP-verified as well.
Step-up verification
Having a session is not enough to move money out. Transfers, withdrawals, QR payments and bill payments require additional verification:
| Method | When |
|---|---|
otpCode | The code sent when the operation was initialized |
trustedActionToken | A previously obtained trusted-action token |
Step-up tokens are single-use. Do not reuse one on a second operation; every money movement demands its own verification.
Rate limiting
Identity endpoints are rate limited — brute force and OTP flooding are blocked. In your app:
- Show a wait time after consecutive failures.
- Gate the resend button behind a countdown.
- Never build an automatic retry loop.
Flow summary
Identify the app
Send requests with the publishable key.
Register or log the user in
register / login → challengeId.
Verify the OTP
otp/verify → session tokens.
Call /me/*
With the access token; only the user's own data.
Step up on outbound money
otpCode or trustedActionToken.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| Registration never completes | OTP not verified | Finish the flow with otp/verify |
| Sessions drop earlier than expected | No refresh flow | Use auth/refresh |
| Money operations return 4xx | Missing step-up | Send otpCode / trustedActionToken |
| You keep hitting rate limits | Automatic retries | Remove the loop, show the user a countdown |