Partner Access Token
The API uses an AES-256-ECB encrypted UTC timestamp to authenticate a channel partner and protect requests from replay attacks.
The same encrypted payload also carries an optional client platform — web, mobile_app or mini_app. That is how a native app is exempted from reCAPTCHA, so it belongs inside the encrypted payload rather than in a header anyone could set.
Credentials
You need the following values from the Channel Partner Profile:
- API Key: public partner identifier.
- Secret Key: private partner secret. Keep it secure and never expose it in client-side code.
Generate the Token in JavaScript
const crypto = require('crypto');
const apiKey = 'YOUR_PUBLIC_API_KEY';
const apiSecret = 'YOUR_PRIVATE_SECRET_KEY';
// 'web' | 'mobile_app' | 'mini_app'
const platform = 'web';
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
const payload = platform === 'web' ? timestamp : `${timestamp}|${platform}`;
const aesKey = apiSecret.substring(0, 32);
const cipher = crypto.createCipheriv('aes-256-ecb', aesKey, null);
cipher.setAutoPadding(true);
let encryptedPayload = cipher.update(payload, 'utf8', 'base64');
encryptedPayload += cipher.final('base64');
const token = Buffer.from(`${apiKey}|${encryptedPayload}`).toString('base64');
Generate the Token in PHP
<?php
$apiKey = 'YOUR_PUBLIC_API_KEY';
$apiSecret = 'YOUR_PRIVATE_SECRET_KEY';
// 'web' | 'mobile_app' | 'mini_app'
$platform = 'web';
$timestamp = gmdate('Y-m-d H:i:s');
$payload = $platform === 'web' ? $timestamp : $timestamp . '|' . $platform;
$aesKey = substr($apiSecret, 0, 32);
$encryptedPayload = openssl_encrypt(
$payload,
'aes-256-ecb',
$aesKey,
0
);
$token = base64_encode($apiKey . '|' . $encryptedPayload);
Client Platform
The encrypted payload is either the timestamp on its own or the timestamp and the platform joined by a pipe:
| Encrypted payload | Resolved platform | reCAPTCHA on checkout |
|---|---|---|
2026-11-06 07:08:19 | web | Required |
2026-11-06 07:08:19|web | web | Required |
2026-11-06 07:08:19|mobile_app | mobile_app | Skipped |
2026-11-06 07:08:19|mini_app | mini_app | Skipped |
2026-11-06 07:08:19|anything-else | web | Required |
Existing tokens that carry only a timestamp keep working and resolve to web, so nothing has
to change unless you want the exemption. An unrecognised platform also resolves to web: the
API always falls back to the stricter browser rules rather than letting a typo through.
See Checkout Security & Bot Protection for what the exemption covers.
:::danger Build the token on a server, never in the browser
The platform claim is trustworthy only because producing the encrypted payload requires your
Secret Key. If that key reaches browser JavaScript, anyone can read it, mint a mobile_app
token and walk past reCAPTCHA. A web frontend must ask its own backend for the token; a native
app holds the key itself or fetches a token from your backend.
:::
Send the Header
Include a freshly generated token on every partner-protected request:
Partner-Access-Token: <token>
fetch('https://api.dev.onlynx.co.th/api/v1/auth/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Partner-Access-Token': token
},
body: JSON.stringify({
credential: 'user@example.com',
password: 'secret123'
})
});
Validity Rules
- The encrypted timestamp must be UTC in
YYYY-MM-DD HH:mm:ssformat. - The platform suffix is optional.
webis assumed when it is missing or unrecognised. - The token expires five minutes after its timestamp.
- A future timestamp is allowed only within 60 seconds for clock drift.
- Generate the token on a trusted backend immediately before each API request.
Authentication Errors
Partner authentication failures return HTTP 401:
{
"error": "Token has expired"
}
Possible messages include Invalid token format, Invalid token structure, Invalid API Key, Invalid token signature, Token has expired, Invalid timestamp, and Invalid timestamp format.