Skip to main content

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:

  1. API Key: public partner identifier.
  2. 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 payloadResolved platformreCAPTCHA on checkout
2026-11-06 07:08:19webRequired
2026-11-06 07:08:19|webwebRequired
2026-11-06 07:08:19|mobile_appmobile_appSkipped
2026-11-06 07:08:19|mini_appmini_appSkipped
2026-11-06 07:08:19|anything-elsewebRequired

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:ss format.
  • The platform suffix is optional. web is 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.