Skip to Content
API ReferenceAuthentication

Authentication

QPay V2 uses a token-based authentication system. You authenticate with your merchant credentials via Basic Auth to obtain an access token, then include that token as a Bearer token in all subsequent API requests.

All QPay SDKs handle this token lifecycle automatically. You typically do not need to call these endpoints directly when using an SDK.


Get Token

POST /v2/auth/token

Authenticates using Basic Auth (username:password) and returns an access token and refresh token pair.

Request

Headers:

HeaderValueRequired
AuthorizationBasic base64(username:password)Yes
Content-Typeapplication/jsonYes

No request body is required.

Example Request

curl -X POST https://merchant.qpay.mn/v2/auth/token \ -H "Authorization: Basic $(echo -n 'YOUR_USERNAME:YOUR_PASSWORD' | base64)" \ -H "Content-Type: application/json"

Response

{ "token_type": "Bearer", "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 600, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_expires_in": 3600, "scope": "...", "not-before-policy": "...", "session_state": "..." }
FieldTypeDescription
token_typestringAlways "Bearer"
access_tokenstringJWT access token for API calls
expires_innumberAccess token TTL in seconds (typically 600 = 10 minutes)
refresh_tokenstringToken used to refresh the access token
refresh_expires_innumberRefresh token TTL in seconds (typically 3600 = 1 hour)
scopestringToken scope
not-before-policystringToken not-before policy timestamp
session_statestringSession state identifier

Error Responses

HTTP StatusError CodeDescription
401AUTHENTICATION_FAILEDInvalid username or password
401NO_CREDENDIALSMissing or malformed Authorization header

Error example:

{ "error_code": "AUTHENTICATION_FAILED", "message": "Invalid username or password" }

Refresh Token

POST /v2/auth/refresh

Uses a refresh token to obtain a new access token pair without re-authenticating with credentials. The refresh token is sent in the Authorization header as a Bearer token.

Request

Headers:

HeaderValueRequired
AuthorizationBearer <refresh_token>Yes
Content-Typeapplication/jsonYes

No request body is required.

Example Request

curl -X POST https://merchant.qpay.mn/v2/auth/refresh \ -H "Authorization: Bearer <refresh_token>" \ -H "Content-Type: application/json"

Response

Same structure as the Get Token response:

{ "token_type": "Bearer", "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 600, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_expires_in": 3600 }
FieldTypeDescription
token_typestringAlways "Bearer"
access_tokenstringNew JWT access token
expires_innumberNew access token TTL in seconds
refresh_tokenstringNew refresh token (the old one is invalidated)
refresh_expires_innumberNew refresh token TTL in seconds

Error Responses

HTTP StatusError CodeDescription
401AUTHENTICATION_FAILEDInvalid or expired refresh token

Token Lifecycle

The recommended authentication flow:

1. Initial Auth POST /v2/auth/token (Basic Auth) | v access_token (10 min) + refresh_token (1 hour) | v 2. Use Access Token All API requests: Authorization: Bearer <access_token> | v 3. Token Expires (after ~10 min) | v 4. Refresh POST /v2/auth/refresh (Bearer refresh_token) | v New access_token + New refresh_token | v 5. Refresh Token Expires (after ~1 hour) | v 6. Re-authenticate Back to Step 1: POST /v2/auth/token

Implementation Guidelines

  • Cache the access token for its TTL minus a safety margin (e.g., expires_in - 30 seconds) to avoid using an expired token
  • Store the refresh token separately with its own TTL
  • On 401 responses, attempt a token refresh before re-authenticating with credentials
  • Thread safety: If your application makes concurrent requests, ensure token refresh is synchronized to avoid race conditions
  • Never expose tokens in client-side code, URLs, or logs

Token Lifetimes

TokenTypical TTLPurpose
Access token600 seconds (10 minutes)Used in API request headers
Refresh token3600 seconds (1 hour)Used to get new access tokens

Both tokens are JWTs (JSON Web Tokens). The access token is signed with RSA (RS256) and the refresh token with HMAC (HS256).


Using Authentication in API Requests

Once you have an access token, include it in the Authorization header of all subsequent API requests:

curl -X POST https://merchant.qpay.mn/v2/invoice \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \ -H "Content-Type: application/json" \ -d '{ ... }'

If the token is expired, you will receive a 401 response:

{ "error_code": "AUTHENTICATION_FAILED", "message": "Token expired or invalid" }

At that point, refresh the token or re-authenticate.

Last updated on