Authentication Guide

Two auth methods, token lifecycle, MFA setup, and security challenges.

Authentication Guide

UrbanPayX offers two authentication methods: email/password login for interactive use, and API key authentication for server-to-server integrations. This guide covers both methods, token management, MFA, and security challenges.


Two ways to authenticate

API key authEmail/password login
EndpointPOST /auth/api-tokenPOST /auth/login
Best forServer-to-server integrations, automated workflowsInteractive dashboard use, admin tasks
RoleAlways operationsRole of the logged-in team member
Access token TTL2 hours30 minutes
Refresh tokenNot issuedIssued (30-day TTL)
MFANot applicableSupported (email OTP or TOTP)

Choose API key auth for your backend integration — it is simpler, has longer-lived tokens, and does not require MFA handling. Use email/password login for dashboard operations or when you need OWNER or DEVELOPER permissions that API keys do not carry.


API key authentication

The simplest way to authenticate. Send your API key and secret, get an access token.

POST /api/v1/auth/api-token
Content-Type: application/json

{
  "api_key": "your-api-key",
  "api_secret": "your-api-secret"
}

Response:

{
  "access_token": "eyJhbGciOi...",
  "token_type": "bearer"
}

The access token is valid for 2 hours. No refresh token is issued — when it expires, authenticate again with your API key.

Important: API key tokens always carry the operations role, regardless of who created the key. This means they can create payments and manage KYC, but cannot manage team members (OWNER only) or configure webhooks (DEVELOPER or OWNER only). See Roles and Permissions for the full matrix.

Rate limiting

After 5 failed authentication attempts, the API key is locked out for 5 minutes. The API returns 429 Too Many Requests with the lockout duration.


Email/password login

For interactive use and operations that require OWNER or DEVELOPER roles.

POST /api/v1/auth/login
Content-Type: application/json

{
  "client_email": "[email protected]",
  "password": "your-password"
}

Without MFA

If MFA is not enabled, you get tokens immediately:

{
  "access_token": "eyJhbGciOi...",
  "refresh_token": "eyJhbGciOi...",
  "token_type": "bearer"
}

With MFA enabled

If MFA is enabled on the account (or enforced by client defaults), the login response includes a challenge:

{
  "token_type": "otp_pending",
  "challenge_token": "base64-encoded-token",
  "requires_mfa": true,
  "allowed_mfa_methods": ["email", "totp"],
  "preferred_mfa_method": "email"
}

Complete the challenge by verifying the OTP:

POST /api/v1/auth/login/verify-otp
Content-Type: application/json

{
  "challenge_token": "base64-encoded-token",
  "otp_code": "123456",
  "method": "email"
}

The challenge token expires after 5 minutes. You have a maximum of 5 attempts to enter the correct code. If using email OTP, there is a 60-second cooldown between resend requests.

If your preferred method is TOTP but you want to fall back to email, use:

POST /api/v1/auth/login/challenge/send-email-code

Rate limiting

After 5 failed login attempts for the same email, the account is locked out for 5 minutes (429 Too Many Requests).


Token lifecycle

Access tokens

Access tokens are JWTs that authenticate every API request. Include them in the Authorization header:

Authorization: Bearer eyJhbGciOi...
Token sourceTTLRefresh available
API key auth2 hoursNo — re-authenticate
Email/password login30 minutesYes — use refresh token

Refresh tokens

Dashboard login tokens come with a refresh token (30-day TTL). Use it to get a new access token without re-entering credentials:

POST /api/v1/auth/refresh
Content-Type: application/json

{
  "refresh_token": "eyJhbGciOi..."
}

Response:

{
  "access_token": "new-access-token",
  "refresh_token": "new-refresh-token",
  "token_type": "bearer"
}

Important: Token refresh uses rotation — each refresh returns a new refresh token and invalidates the old one. Always store and use the latest refresh token.

Token payload

Access tokens contain these claims:

ClaimDescription
subYour client ID
typeToken type (client_access or client_api_access)
actor_typeclient_user (login) or client_api (API key)
roleowner, operations, or developer
account_idTeam member account ID (login tokens only)
expExpiration timestamp

Logout

To revoke tokens and end a session:

POST /api/v1/auth/logout
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "refresh_token": "your-refresh-token"
}

This revokes both the access token and the refresh session. The refresh token field is optional — if omitted, only the access token is revoked.


MFA (Multi-Factor Authentication)

MFA adds a second verification step to dashboard logins. It supports two methods: email OTP and TOTP (authenticator app).

MFA policy hierarchy

MFA can be configured at two levels:

  1. Client defaults — Apply to all team members unless overridden. Managed by OWNER or OPERATIONS roles via GET/PUT /auth/mfa/client-defaults.
  2. Account overrides — Individual team members can override the client defaults (if mfa_use_client_default is set to false). Managed via GET/PUT /auth/mfa/me.

Setting up TOTP

To enable authenticator app support:

Step 1 — Start enrollment:

POST /api/v1/auth/mfa/totp/enroll/start
Authorization: Bearer YOUR_ACCESS_TOKEN

Returns a secret key and otpauth_uri that you scan with your authenticator app (Google Authenticator, Microsoft Authenticator, etc.). The enrollment session lasts 10 minutes.

Step 2 — Confirm enrollment:

POST /api/v1/auth/mfa/totp/enroll/confirm
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "enrollment_token": "token-from-step-1",
  "otp_code": "123456"
}

Enter the 6-digit code from your authenticator app to confirm. TOTP codes refresh every 30 seconds, and the system accepts codes within a 1-step window.

Disabling TOTP

Disabling TOTP is a sensitive action that requires a security challenge (see below):

POST /api/v1/auth/mfa/totp/disable
Authorization: Bearer YOUR_ACCESS_TOKEN
X-Security-Token: challenge-token
X-Security-Code: 123456
X-Security-Method: email

Security challenges

Certain high-impact operations require an additional verification step beyond your access token. These operations include:

ActionDescription
ADD_MEMBERCreating a new team account
UPDATE_MEMBERModifying a team account
DELETE_MEMBERRemoving a team account
CHANGE_PASSWORDChanging your account password
REFRESH_API_KEYRotating your API credentials
DISABLE_TOTPDisabling authenticator app MFA

How security challenges work

Step 1 — Request a security code:

POST /api/v1/auth/security/request-code
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "action": "ADD_MEMBER",
  "method": "email"
}

This sends a one-time code to your email (or you can use "totp" if you have an authenticator set up). The response includes a challenge_token that expires in 5 minutes.

Step 2 — Include the security headers in your request:

POST /api/v1/auth/team/accounts
Authorization: Bearer YOUR_ACCESS_TOKEN
X-Security-Token: challenge-token-from-step-1
X-Security-Code: 123456
X-Security-Method: email
Content-Type: application/json

{
  "email": "[email protected]",
  "full_name": "New Member",
  "role": "developer"
}

You have 5 attempts to enter the correct code before the challenge is invalidated.


Client registration

New client registration follows this flow:

  1. Register: POST /auth/register with email, password, and company details
  2. Verify email: A verification code is sent to the registered email (valid for 24 hours)
  3. Confirm: POST /auth/register/verify-email with the code
  4. Login: Use the registered credentials to authenticate

If you need to resend the verification code, use POST /auth/register/resend-verification (60-second cooldown between resends).

Note: Client registration may be disabled. If you receive a 403 error, contact the UrbanPayX team to get your account provisioned.


Password management

Changing your password

Password changes require a security challenge:

POST /api/v1/auth/team/accounts/me/change-password
Authorization: Bearer YOUR_ACCESS_TOKEN
X-Security-Token: challenge-token
X-Security-Code: 123456
X-Security-Method: email
Content-Type: application/json

{
  "current_password": "old-password",
  "new_password": "new-password"
}

The new password must be at least 8 characters and must differ from the current password.


Quick reference

ValueDuration
API key access token TTL2 hours
Dashboard access token TTL30 minutes
Refresh token TTL30 days
OTP code TTL5 minutes
OTP max attempts5
OTP resend cooldown60 seconds
TOTP enrollment TTL10 minutes
Security challenge TTL5 minutes
Login lockout (after 5 failures)5 minutes
Email verification TTL24 hours

Related guides