Overview
The authentication system provides secure user login with optional OTP (One-Time Password) for enhanced security. After successful authentication, users receive an access token valid for 6 hours that authorizes all authenticated API calls.All authentication endpoints require the
x-client-key header. For US environment routing, include x-us-env: true header or region=us query parameter.Authentication Methods
The platform supports multiple authentication patterns:Standard Login
Username/password authentication for direct API access
OTP-Enhanced Login
Multi-factor authentication with SMS verification codes
OAuth 2.0
Delegated authorization for third-party applications
Session Management
Token-based sessions with 6-hour expiration
Login Flow Diagram
Standard Login
Direct authentication using email and password credentials.Endpoint
POST /v1/auth/login
Request
Response (Standard Login)
When OTP is not required:Response (OTP Required)
When OTP is required:Response Fields
Each field in the login response provides critical information about the user’s authentication state and onboarding progress:| Field | Type | Description |
|---|---|---|
accessToken | string | null | Bearer token for authenticated API calls (valid 6 hours). null when user is onboarding or OTP is required |
userId | string | Unique user identifier in UUID format. Always returned |
isOtpRequired | boolean | Indicates if 2FA is enabled. When true, call /v1/auth/login/otp to send OTP, then retry login with otpCode |
phoneNumber | string | null | Masked phone number (e.g., “+445*****225”). Only returned when isOtpRequired is true |
phase | string | null | User’s onboarding progress. Non-null values (ACCOUNT, PHONE_NUMBER, PERSONAL_INFORMATION, PHYSICAL_ADDRESS, MAILING_ADDRESS) mean registration is incomplete. null when onboarding is complete |
verificationState | string | null | KYC verification status: UNVERIFIED (0), PENDING (1), VERIFIED (3), REJECTED (2) |
isLinked | boolean | Indicates if your OAuth client already has permission to access this user’s account |
Detailed Field Explanations
Detailed Field Explanations
phase (string | null)
- Indicates where the user is in the onboarding process
- If null: User has completed all registration steps
- If non-null: User needs to complete registration at the indicated phase
ACCOUNT: Basic account creation stepPHONE_NUMBER: Phone verification stepPERSONAL_INFORMATION: Personal details collectionPHYSICAL_ADDRESS: Physical address informationMAILING_ADDRESS: Mailing address information
- User’s unique identifier in UUID format
- Consistent across all sessions and API calls
- Use this to track user sessions and for OTP requests
- When
true: User has 2FA enabled and must verify with OTP code - When
false: Login is complete, use theaccessTokenfor API calls - OTP flow: Call
/v1/auth/login/otp→ User receives SMS → Retry/loginwithotpCode
- Only present when
isOtpRequiredistrue - Masked for security (e.g., “+445*****225”)
- Shows where the OTP code will be sent
- Display this to users so they know which device to check
- Bearer token for Authorization header:
Authorization: Bearer {token} - Valid for 6 hours (21,600 seconds)
- null in these scenarios:
- User is still onboarding (
phaseis non-null) - OTP verification is required (
isOtpRequiredistrue) - Initial login step before OTP completion
- User is still onboarding (
- non-null when authentication is complete and user can access API
- Maps to KYC verification status:
UNVERIFIED(0): User has not yet been verifiedPENDING(1): Verification is in progressVERIFIED(3): User is successfully verifiedREJECTED(2): Verification was rejected
- Check this before allowing access to features requiring verified users
- Indicates OAuth connection status between your client and this user
false: Your OAuth client needs to complete OAuth flow for long-lived accesstrue: Your client already has OAuth tokens and can refresh them- Important for determining whether to initiate OAuth flow after login
Edge Cases and Response Scenarios
Understanding different response scenarios helps you handle all authentication states correctly:- User Still Onboarding
- OTP Required
- Successful Login
- OAuth Linking Status
When a user hasn’t completed registration, the response indicates their current phase:What this means:
- User is stuck at the
PHONE_NUMBERverification phase - No
accessTokenprovided because onboarding is incomplete verificationStateis null because KYC hasn’t started yet
- Direct user to continue registration flow
- Guide them to the phone verification step
- Don’t attempt to use the API until
phaseisnull
Using the Access Token
After successful login, use the access token in theAuthorization header for all authenticated API calls:
Access tokens expire after 6 hours. Implement token refresh logic or require re-authentication when tokens expire.
Common Errors
Invalid Credentials
Invalid Credentials
Account Not Found
Account Not Found
Account Locked
Account Locked
OTP Authentication
For users with OTP enabled, an additional verification step is required after initial login.OTP Flow
Step 1: Check OTP Requirement
After initial login, check theisOtpRequired field:
Step 2: Send OTP Code
Request an OTP code to be sent via SMS to the user’s registered phone number.Endpoint
POST /v1/auth/login/otp
Request
Response
OTP codes are typically valid for 5-10 minutes. Users should enter the code promptly after receiving it.
Step 3: Submit OTP Code
Complete login by submitting the OTP code along with the original credentials.Request
Response
After successful OTP verification,
isOtpRequired will be false and the accessToken is fully valid for API calls.Common OTP Errors
Invalid OTP Code
Invalid OTP Code
OTP Code Expired
OTP Code Expired
POST /v1/auth/login/otpToo Many OTP Attempts
Too Many OTP Attempts
Complete OTP Login Example
Here’s a complete implementation of the OTP login flow:Session Management
Token Expiration
Access tokens are valid for 6 hours from the time of issuance. After expiration, users must re-authenticate.Token Storage
Store access tokens securely based on your application type: Web Applications:- Use secure storage mechanisms (iOS Keychain, Android Keystore)
- Never store tokens in plain text files or shared preferences
- Store in memory or secure session stores (Redis, database)
- Use encryption for persistent storage
Token Validation
Before making API calls, validate the token hasn’t expired:Logout
Terminate the current user session and invalidate the access token.Endpoint
POST /v1/auth/logout
Request
Response
After logout, the access token is immediately invalidated and cannot be used for further API calls.
Login Access Token vs OAuth Tokens
Understanding the difference between login access tokens and OAuth tokens helps you choose the right authentication method for your use case.Why Exchange Tokens at the OAuth Authorize Endpoint?
Even though the loginaccessToken works for API calls, OAuth tokens provide significant advantages for production applications:
Login Access Token
Short-Term Direct AccessLimitations:
- Expires in 6 hours (21,600 seconds)
- Cannot be refreshed
- Cannot be revoked independently
- No granular permission scopes
- Quick authentication for first-party apps
- Short user sessions
- Testing and development
- Simple integrations
OAuth Tokens
Long-Lived Delegated AccessAdvantages:
- Refresh tokens last 7 days (604,800 seconds) for security compliance with financial operations
- Can obtain new access tokens without re-login
- Can be revoked via
/oauth/revokeendpoint - PKCE security (S256 code challenge) prevents interception
- Proper delegation model for third-party apps
- Granular permission management
- Long-lived access
- Third-party integrations
- Mobile applications
- Multi-tenant applications
Token Comparison Table
| Feature | Login Access Token | OAuth Access Token |
|---|---|---|
| Lifetime | 6 hours | 6 hours |
| Obtained From | POST /v1/auth/login | POST /v1/auth/oauth/token |
| Refresh Capability | None | Via refresh token |
| Refresh Token Lifetime | N/A | 7 days |
| Revocation | Expires only | Can be revoked |
| Security Model | Direct credentials | PKCE + OAuth 2.0 |
| Use Case | First-party, short sessions | Third-party, long-lived access |
| Best Practice | Development & testing | Production applications |
Use Case Examples
- Use Login Token When
- Use OAuth Tokens When
Scenario 1: First-Party Web AppScenario 2: Short Testing SessionScenario 3: Admin Tools
- Internal admin dashboards
- Short-lived debugging sessions
- One-time data exports
Migration Strategy
If you’re currently using login access tokens:1
Identify Long-Lived Sessions
Determine which parts of your application need access beyond 6 hours
2
Implement OAuth Flow
Add OAuth 2.0 authorization for those long-lived sessions
3
Implement Token Refresh
Use refresh tokens to maintain sessions without re-authentication
4
Test Revocation
Ensure your app handles token revocation gracefully
5
Monitor Token Expiry
Track refresh token expiration (7 days) and prompt re-authentication
OAuth 2.0 Authentication
For third-party applications, OAuth 2.0 provides delegated authorization without exposing user credentials.OAuth Flow Overview
- Hosted UI Mode (4 Steps)
- API Mode (5 Steps)
- Token Types Explained
- PKCE Implementation
When to Use OAuth
Use OAuth 2.0 when:- Building third-party integrations
- Providing API access to external partners
- Creating multi-tenant applications
- Implementing “Login with [Your Service]” buttons
Quick Start
OAuth 2.0 implementation involves 4 steps:1
Initiate Authorization
Request authorization from the user via
GET /v1/auth/oauth/authorize/initiate2
User Authentication
User authenticates on hosted UI (or via API-mode login)
3
Generate Authorization Code
Receive authorization code after user approval
4
Exchange for Tokens
Exchange code for access and refresh tokens via
POST /v1/auth/oauth/tokenFor complete OAuth 2.0 implementation details, see the OAuth 2.0 Guide and API reference documentation.
OAuth vs Standard Login
| Feature | Standard Login | OAuth 2.0 |
|---|---|---|
| Use Case | First-party apps | Third-party integrations |
| User Credentials | Handled by your app | Never exposed to your app |
| Token Lifetime | 6 hours | Access: 6 hours, Refresh: 7 days |
| Token Refresh | Re-authenticate | Use refresh token |
| Delegation | Direct access | Scoped permissions |
Best Practices
Secure Storage
Always store access tokens securely. Never expose tokens in URLs, logs, or client-side code repositories.
HTTPS Only
All authentication requests must use HTTPS in production. Never send credentials over unencrypted connections.
Rate Limiting
Implement exponential backoff for failed login attempts to prevent brute force attacks.
Token Rotation
Rotate tokens periodically and after sensitive operations. Invalidate tokens on password changes.
Error Handling
Don’t leak sensitive information in error messages. Use generic messages like “Invalid credentials” instead of “User not found” or “Wrong password”.
OTP Timeout
Implement countdown timers for OTP codes to improve UX. Show “Resend code” option after timeout.
Security Considerations
Password Security
- Never store passwords in plain text
- Use secure password hashing (bcrypt, Argon2)
- Implement password strength requirements
- Enforce password rotation policies
- Prevent password reuse
Multi-Factor Authentication
OTP provides an additional security layer:- SMS-based codes (current implementation)
- Consider supporting authenticator apps (TOTP)
- Implement backup codes for account recovery
- Allow users to enable/disable MFA
Account Protection
- Lock accounts after multiple failed login attempts
- Implement CAPTCHA after failed attempts
- Send security alerts for suspicious logins
- Log all authentication events for audit
Token Security
- Use short-lived access tokens (6 hours)
- Implement token rotation for refresh tokens
- Invalidate all tokens on password change
- Provide “Log out all devices” functionality
Troubleshooting
Login Failures
Credentials Work in One Environment But Not Another
Credentials Work in One Environment But Not Another
Cause: Trying to use production credentials in sandbox or vice versaResolution: Ensure you’re using the correct
x-us-env header and credentials for each environmentToken Rejected by API
Token Rejected by API
Cause: Token expired, invalid format, or wrong environmentResolution:
- Check token expiration (6-hour limit)
- Verify token format includes environment prefix (e.g., “US_…”)
- Ensure
x-client-keymatches the environment that issued the token
OTP Not Received
OTP Not Received
Cause: Phone number issues, carrier blocking, or delayResolution:
- Verify phone number is correct and can receive SMS
- Check spam/blocked messages on device
- Wait 2-3 minutes for delivery delays
- Request a new code if needed
Integration Issues
Common issues when integrating authentication: Missing Headers:Complete Authentication Example
Full implementation with error handling and token management:Next Steps
After successful authentication:- Make Authenticated Requests: Use the access token for all API calls
- Check Verification Status: Verify user’s KYC status via Profile Management
- Implement Token Refresh: Plan for token expiration and re-authentication
