Authentication
Overview
FutureSMS Merchant API uses Bearer access tokens. A client logs in with an API user, stores the returned token pair, sends the access token on business requests, and refreshes the token pair before continuing.
Authentication also checks whether the user, account, role, and session are allowed to use the requested API surface.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/auth/login | Authenticate a user and issue a token pair. |
POST | /api/v1/auth/refresh | Rotate the refresh token and issue a new token pair. |
GET | /api/v1/auth/me | Verify the access token and read the current profile. |
POST | /api/v1/auth/logout | Revoke the current session. |
Before You Begin
Create a dedicated API user for server-to-server Merchant API access. Do not reuse a human portal account for automated traffic.
Make sure the integration can persist the latest token pair, coordinate token refresh across workers, and use UTC timestamps from the auth response when deciding when to refresh.
Request Flow
- Call
POST /api/v1/auth/loginwithusernameandpassword. - Store
access_token,refresh_token, and both expiry timestamps. - Send
Authorization: Bearer <access_token>on protected API requests. - When the access token expires, call
POST /api/v1/auth/refreshwith the latest refresh token. - Replace both stored tokens with the refresh response.
- Call
POST /api/v1/auth/logoutwhen the integration should end the session.
Authorization Header
Authentication-protected endpoints use the same header shape.
{
"Authorization": "Bearer <access_token>"
}
Login
Use Login when your integration needs to start a Merchant API session and obtain a token pair.
Endpoint
POST /api/v1/auth/login
Authentication: none.
Before You Begin
Use an API user for server-to-server Merchant API integrations. Portal users can authenticate for portal flows, but merchant business API usage should not depend on a human portal session.
The user must be active and allowed to use the requested API surface.
Request fields
| Field | Type | Required | Rules |
|---|---|---|---|
username | string | Yes | 4-64 chars, A-Z, a-z, 0-9, and _. |
password | string | Yes | 8-72 chars. |
Response fields
| Field | Meaning |
|---|---|
mfa_required | Whether the account requires an additional authentication step before a token pair can be used. |
mfa_token | Temporary MFA token when MFA is required; otherwise null. |
access_token | Bearer token for protected API requests. |
refresh_token | Token used only with /api/v1/auth/refresh. |
token_type | Token scheme, normally bearer. |
access_token_expires_at | UTC timestamp when the access token expires. |
refresh_token_expires_at | UTC timestamp when the refresh token expires. |
user.username | Authenticated username. |
user.role | Authenticated role, such as api, merchant_admin, or site_admin. |
Behavior
When login succeeds, FutureSMS:
- Applies login protection checks.
- Validates username and password.
- Confirms the user can authenticate for this API surface.
- Checks the account and role permissions.
- Handles MFA state if the account requires it.
- Replaces older sessions for the same user.
- Issues a new access token and refresh token.
New login can replace older sessions for the same user. If an old token stops working after a new login, log in again and update stored credentials.
Status codes
| Status | Reason | Meaning |
|---|---|---|
200 | null | Login succeeded and returned an auth response. |
401 | INVALID_CREDENTIALS | Username or password is wrong. |
401 | USER_LOCKED | Account is temporarily locked. |
401 | USER_INACTIVE | User is disabled or no longer active. |
403 | null | User is not allowed for this access scope. |
422 | null | Request body failed validation. |
429 | AUTH_LOGIN_RATE_LIMITED | Too many login attempts. |
Examples
{
"username": "api_user_example",
"password": "REPLACE_WITH_STRONG_PASSWORD"
}
{
"message": "OK",
"details": null,
"data": {
"mfa_required": false,
"mfa_token": null,
"access_token": "<access_token>",
"refresh_token": "<refresh_token>",
"token_type": "bearer",
"access_token_expires_at": "2026-03-25T11:30:00Z",
"refresh_token_expires_at": "2026-04-01T10:30:00Z",
"user": {
"username": "api_user_example",
"role": "api"
}
},
"meta": null
}
Token Storage
Store tokens on the server side of your integration when possible. Treat both tokens as credentials.
| Token | Use |
|---|---|
access_token | Sent on API requests through the Authorization header. |
refresh_token | Sent only to /api/v1/auth/refresh to obtain a new token pair. |
Access tokens are short-lived. Refresh tokens live longer, but can still become invalid before their timestamp if the user logs in again, logs out, changes password, is disabled, or the session is ended.
Refresh
Use Refresh when the access token is expired or close to expiry and the integration should continue the same authenticated session.
Endpoint
POST /api/v1/auth/refresh
Authentication: refresh token in request body.
Before You Begin
Use the latest refresh token only. A successful refresh rotates the pair, so the previous refresh token should be treated as spent.
If multiple workers share one API user, coordinate refresh so only one worker rotates the session and the others reuse the stored new token pair.
Request fields
| Field | Type | Required | Rules |
|---|---|---|---|
refresh_token | string | Yes | Latest refresh token from login or the previous refresh response. |
Response fields
| Field | Meaning |
|---|---|
mfa_required | Usually false for server-to-server API refresh. |
mfa_token | Temporary MFA token if an additional authentication step is required. |
access_token | New Bearer token for protected API requests. |
refresh_token | New refresh token. Store this and discard the previous one. |
token_type | Token scheme, normally bearer. |
access_token_expires_at | UTC timestamp when the new access token expires. |
refresh_token_expires_at | UTC timestamp when the new refresh token expires. |
user.username | Authenticated username after revalidation. |
user.role | Authenticated role after revalidation. |
Behavior
Refresh revalidates the session before issuing a new pair. FutureSMS:
- Verifies the refresh token.
- Confirms the session can continue.
- Rechecks user, account, and role permissions.
- Applies refresh protection checks.
- Issues a new token pair.
After a successful refresh, store the new refresh token and discard the previous one. If several workers need to refresh, let one worker refresh and share the updated token pair with the others.
Status codes
| Status | Reason | Meaning |
|---|---|---|
200 | null | Refresh succeeded and returned a new token pair. |
401 | REFRESH_TOKEN_EXPIRED | Refresh token expired. |
401 | REFRESH_TOKEN_REVOKED | Refresh token was already rotated or revoked. |
401 | REFRESH_TOKEN_KICKED | A newer login replaced this refresh session. |
401 | REFRESH_TOKEN_IDLE_EXPIRED | Refresh session expired from inactivity. |
401 | USER_LOCKED | Account is temporarily locked. |
401 | USER_INACTIVE | User is disabled or no longer active. |
403 | null | User is not allowed for this access scope. |
422 | null | Request body failed validation. |
429 | AUTH_REFRESH_RATE_LIMITED | Too many refresh attempts. |
Examples
{
"refresh_token": "<refresh_token>"
}
{
"message": "OK",
"details": null,
"data": {
"mfa_required": false,
"mfa_token": null,
"access_token": "<new_access_token>",
"refresh_token": "<new_refresh_token>",
"token_type": "bearer",
"access_token_expires_at": "2026-03-25T12:30:00Z",
"refresh_token_expires_at": "2026-04-01T11:30:00Z",
"user": {
"username": "api_user_example",
"role": "api"
}
},
"meta": null
}
Current User
Use Current User to check whether the current access token is valid and to read the current user and merchant summary.
Endpoint
GET /api/v1/auth/me
Authentication: Bearer access token.
Before You Begin
Send a current access token in the Authorization header. This endpoint is useful for startup checks and diagnostics, but each business endpoint still performs its own authorization checks.
Request fields
No JSON request body. Send the access token in the Authorization header.
Response fields
| Field | Meaning |
|---|---|
current_user.username | Current authenticated username. |
current_user.email | User email address. |
current_user.role | Current role. |
current_user.is_active | Whether the user is active. |
merchant.merchant_id | Merchant logical identifier, when the user belongs to a merchant. |
merchant.name | Merchant display name. |
merchant.merchant_prepaid_cash | Account prepaid balance, when exposed to the caller. |
merchant.merchant_credit_available | Account credit availability, when exposed to the caller. |
merchant.is_active | Whether the merchant account is active. |
Behavior
FutureSMS validates the access token and session state before returning the profile. This endpoint is useful for startup checks and operator diagnostics, but it should not replace endpoint-specific validation.
Status codes
| Status | Reason | Meaning |
|---|---|---|
200 | null | Token is valid and profile data was returned. |
401 | TOKEN_EXPIRED | Access token expired. |
401 | TOKEN_INVALID | Token cannot be decoded or verified. |
401 | TOKEN_REVOKED | Access token was revoked. |
401 | TOKEN_KICKED | A newer login replaced this session. |
401 | TOKEN_IDLE_EXPIRED | Portal-role session expired from inactivity. |
401 | USER_INACTIVE | User is disabled or no longer active. |
403 | null | User is not allowed for this access scope. |
Examples
{
"message": "OK",
"details": null,
"data": {
"current_user": {
"username": "api_user_example",
"email": "api-user@example.com",
"role": "api",
"is_active": true
},
"merchant": {
"merchant_id": "MCH-1",
"name": "Merchant A",
"merchant_prepaid_cash": "0.000000",
"merchant_credit_available": "0.000000",
"is_active": true
}
},
"meta": null
}
Logout
Use Logout when the integration should explicitly end the current session.
Endpoint
POST /api/v1/auth/logout
Authentication: Bearer access token.
Before You Begin
Call logout when your integration intentionally ends a session or rotates to a different API user. After logout succeeds, remove the stored access token and refresh token from your integration.
Request fields
No JSON request body. Send the access token in the Authorization header.
Response fields
| Field | Meaning |
|---|---|
message | Usually OK when the logout request was accepted. |
data | null for logout. |
details | Additional details, normally null. |
meta | Additional metadata, normally null. |
Behavior
Logout ends the current session. After logout succeeds, clear the stored access token and refresh token.
Status codes
| Status | Reason | Meaning |
|---|---|---|
200 | null | Logout succeeded. |
401 | TOKEN_EXPIRED | Access token expired. |
401 | TOKEN_INVALID | Token cannot be decoded or verified. |
401 | TOKEN_REVOKED | Access token was revoked. |
401 | TOKEN_KICKED | A newer login replaced this session. |
Examples
{
"message": "OK",
"data": null,
"details": null,
"meta": null
}
Session Rules
FutureSMS sessions can end before the token timestamp when account or session state changes.
| Rule | Meaning for integrations |
|---|---|
| New login can replace older sessions | If the same user logs in again, older tokens may stop working. |
| Refresh returns a new token pair | Always replace the stored access and refresh tokens after refresh succeeds. |
| Logout ends the current session | After logout, the same access token should not be reused. |
| User state is rechecked | Disabled users cannot continue with old tokens. |
| Access policy is rechecked | Role and account access rules are enforced where required. |
| Portal idle timeout applies to portal roles | site_admin and merchant_admin sessions can expire from inactivity. API users are intended for server-to-server use. |
Access Scope
Roles map to different access scopes.
| Role | Scope |
|---|---|
site_admin | ADMIN_PORTAL |
merchant_admin | MERCHANT_PORTAL |
api | API |
For Merchant API integrations, use an api user. Login and protected API calls can be rejected if the user, merchant, or role does not satisfy the configured access rules.
MFA Field
The login and refresh response shape includes mfa_required and mfa_token because the shared auth response supports MFA. For normal server-to-server Merchant API usage, an API user should receive access and refresh tokens directly.
If mfa_required is true, no usable Merchant API token pair has been issued yet. Complete the account's authentication flow or contact your FutureSMS administrator before using business endpoints.
Client Guidance
Only one worker should refresh a session at a time. If several API calls all receive TOKEN_EXPIRED, let one refresh request rotate the token pair and make the others reuse the new tokens.
For long-running jobs, refresh before starting a large batch if the access token is close to expiry. For business requests, never retry forever on auth errors: after one successful refresh attempt, a repeated 401 should be treated as a new login or operator action problem.