Authorization Introduction
Learn the Pexx authorization flow, signing rules, headers, and credential request requirements for merchant integrations.
Scope
This document describes the authorization flow for merchants integrating with the Pexx service B2B APIs. It only covers authorization-related content and does not include detailed business API specifications.
Basic Integration Information
API Base URLs
| Environment | Base URL |
|---|---|
| Sandbox | https://qa.saas.pexx.com |
| Production | https://saas.backend.pexx.com |
Merchant Onboarding Materials
Before integration, key exchange and merchant configuration must be completed.
-
The merchant generates its own RSA key pair.
-
The merchant provides the RSA public key to the
Pexx servicefor storage. -
The RSA private key must be securely stored by the merchant. The
Pexx servicedoes not store the merchant's private key. -
After merchant configuration is completed, the
Pexx serviceprovides the following information:merchantCode: merchant identifierPexxApiKey: merchant API key
A 2048-bit RSA key is recommended.
Example: Generate RSA Key Pair
Use OpenSSL to generate the RSA key pair:
# 1. Generate a 2048-bit RSA private key
openssl genrsa -out merchant_private_key.pem 2048
# 2. Convert the private key to PKCS#8 (PEM)
openssl pkcs8 -topk8 -inform PEM -outform PEM -in merchant_private_key.pem -out merchant_private_key_pkcs8.pem -nocrypt
# 3. Export the public key (provide this file to the Pexx service)
openssl rsa -in merchant_private_key.pem -pubout -out merchant_public_key.pem
# 4. Convert the PKCS#8 private key to a single-line Base64 string for signing
grep -v '^-----' merchant_private_key_pkcs8.pem | tr -d '\r\n' > merchant_private_key.txt# Windows PowerShell equivalent of step 4
(Get-Content merchant_private_key_pkcs8.pem | Where-Object { $_ -notmatch '^-----' }) -join '' |
Set-Content -NoNewline merchant_private_key.txtNotes:
| File | Format | Used for |
|---|---|---|
merchant_public_key.pem | PEM, including the -----BEGIN PUBLIC KEY----- header and footer | Provided to the Pexx service during onboarding |
merchant_private_key.txt | Single-line Base64 PKCS#8. No -----BEGIN/END PRIVATE KEY----- header or footer, and no line breaks | Signing X-SIGNATURE on access-token and refresh-token, and signing X-MERCHANT-SIGNATURE |
The value in merchant_private_key.txt starts with MIIE and is one line (about 1,620–1,630 characters for a 2048-bit key). Keep this file secret. The Pexx service never stores your private key.
Glossary
| Term | Description |
|---|---|
merchantCode | The unique merchant identifier assigned by the Pexx service |
PexxApiKey | The API key assigned by the Pexx service and used to identify the merchant |
accessToken | The access token used for business API calls and passed in PexxAuthorization |
refreshToken | The token used to refresh access credentials |
secretKey | The signing key used to generate HMAC signatures for business API requests |
grantType | The credential application type; for the current integration, client_credentials is recommended |
X-TIMESTAMP | Unix timestamp in seconds; should use the current time when the request is sent |
X-NONCE | A unique random string for each request to prevent replay attacks; recommended maximum length is 32 characters, and a UUID without hyphens is recommended |
X-SIGNATURE | The request signature value, generated according to the signing rules in this document and then Base64-encoded |
| X-MERCHANT-SIGNATURE | An additional RSA signature for business API requests. It is required only when Pexx has enabled merchant signature verification for your merchant. It uses the same string to sign as X-SIGNATURE, but it is signed with your RSA private key. |
path | The actual request path, for example /apis/v1/access-token |
Authorization Flow
1. Request Access Credentials
Call:
POST /apis/v1/access-token
Purpose:
- Request business access credentials
- Obtain the
accessToken,refreshToken, andsecretKeyrequired for subsequent business API calls
Optional: Follow the cURL walkthrough in Recipes
Open the Request an access token with cURL Recipe to see the request body, required headers, cURL command, and example success and failure responses side by side.
Use this page for the signing rules and parameter definitions, then use the Recipe when you want a request flow you can copy and adapt.
2. Call Business APIs
Applicable range:
GET /apis/v1/**POST /apis/v1/**
Purpose:
- Use
accessTokento access business APIs - Use
secretKeyto generate the request signature for business APIs
3. Refresh Access Credentials
Call:
POST /apis/v1/refresh-token
Purpose:
- Request a new set of access credentials after
accessTokenexpires by usingrefreshToken
API Integration Details
Header Requirements
Common Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json |
PexxApiKey | Yes | Merchant API key |
X-TIMESTAMP | Yes | Unix timestamp in seconds |
X-NONCE | Yes | Unique random string for each request; recommended maximum length is 32 characters |
X-SIGNATURE | Yes | Request signature, Base64-encoded |
Additional Header for Business APIs
| Header | Required | Description |
|---|---|---|
PexxAuthorization | Yes | Format: Bearer {accessToken} |
| X-MERCHANT-SIGNATURE | No | Additional RSA signature, Base64-encoded. Required only when Pexx enabled your merchant signature verification. It does not replace X-SIGNATURE. |
Signing Rules
1. Signature for access-token / refresh-token Requests ( X-SIGNATURE, required )
access-token / refresh-token Requests ( X-SIGNATURE, required )Applicable APIs:
POST /apis/v1/access-tokenPOST /apis/v1/refresh-token
Signature algorithm:
SHA256withRSA
String to sign:
METHOD:path:sha256(minifyJson(body)):apiKey:merchantCode:timestamp:nonceExample:
POST:/apis/v1/access-token:sha256(minifyJson(body)):your-api-key:your-merchant-code:1714291200:6f2e7c1a4d9b4c2f9c7d1e3a5b6f8a0cNotes:
METHODmust be uppercase, for examplePOSTpathmust use the actual request path, for example/apis/v1/access-tokenbodymust be serialized in a stable format before hashing- The signature result must be Base64-encoded and passed in
X-SIGNATURE - The private key used for signing must be the single-line Base64 PKCS#8 string in
merchant_private_key.txt. Do not pass the PEM file contents.Base64.getDecoder().decode(...)fails when the value contains-----BEGIN,-----END, or line breaks. minifyJson(body)uses this stable format: sort only the top-level fields alphabetically; leave nested objects unchanged; keep fields whose value is null; writeBigDecimalvalues as plain numbers, not scientific notation.
package com.pexx.core.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
/**
* @ClassName GetAccessTokenTest
**/
public class GetAccessTokenTest {
private static final String DEFAULT_BASE_URL = "http://qa.saas.pexx.com";
private static final String DEFAULT_ACCESS_TOKEN_PATH = "/apis/v1/access-token";
public static void main(String[] args) throws Exception {
// configuration (please modify according to actual situation)
String merchantCode = "your-merchant-code";
String apiKey = "your-api-key";
// Single-line Base64 PKCS#8 from merchant_private_key.txt. No PEM header, footer, or line breaks.
String privatekey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// Build call request body
String body = buildAccessTokenBody(merchantCode);
// current time
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String nonce = UUID.randomUUID().toString().replace("-", "");
// Generate fields to be signed
String stringToSign = buildAccessTokenSignString(
"POST",
DEFAULT_ACCESS_TOKEN_PATH,
body,
apiKey,
merchantCode,
timestamp,
nonce
);
// generate signature
String signature = signRsa(privatekey, stringToSign);
Map<String, String> headers = new LinkedHashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("PexxApiKey", apiKey);
headers.put("X-TIMESTAMP", timestamp);
headers.put("X-NONCE", nonce);
headers.put("X-SIGNATURE", signature);
SignedRequest signedRequest = new SignedRequest("POST", DEFAULT_ACCESS_TOKEN_PATH, headers, body);
System.out.println("=== ACCESS TOKEN REQUEST ===");
System.out.println(toCurl(DEFAULT_BASE_URL, signedRequest));
}
private static String buildAccessTokenBody(String merchantCode) {
Map<String, Object> body = new LinkedHashMap<String, Object>();
body.put("grantType", "client_credentials");
body.put("merchantCode", merchantCode);
return JSON.toJSONString(body);
}
public static String buildAccessTokenSignString(String method, String path, String body, String apiKey, String merchantCode,
String timestamp, String nonce) {
return String.format("%s:%s:%s:%s:%s:%s",
method.toUpperCase(),
path,
sha256Lower(minifyJson(body)),
apiKey,
merchantCode,
timestamp + ":" + nonce);
}
/**
* rsa sign
* @param privateKeyBase64
* @param stringToSign
* @return
* @throws Exception
*/
private static String signRsa(String privateKeyBase64, String stringToSign) throws Exception {
byte[] decoded = Base64.getDecoder().decode(privateKeyBase64);
PrivateKey privateKey = buildPrivateKey(decoded);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(stringToSign.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(signature.sign());
}
/**
* minify json
* @param body
* @return
*/
public static String minifyJson(String body) {
if (body == null || body.trim().isEmpty()) {
return "";
}
try {
Object parsed = JSON.parse(body);
if (!(parsed instanceof JSONObject)) {
return JSON.toJSONString(parsed);
}
JSONObject jsonObject = (JSONObject) parsed;
JSONObject sorted = new JSONObject();
jsonObject.keySet().stream().sorted().forEach(key -> sorted.put(key, jsonObject.get(key)));
return JSON.toJSONString(sorted, JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteBigDecimalAsPlain);
} catch (Exception e) {
return body.trim();
}
}
public static String sha256Lower(String input) {
return DigestUtils.sha256Hex(input == null ? "" : input).toLowerCase();
}
private static PrivateKey buildPrivateKey(byte[] keyBytes) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
try {
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
} catch (Exception ex) {
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(wrapPkcs1ToPkcs8(keyBytes)));
}
}
private static byte[] wrapPkcs1ToPkcs8(byte[] pkcs1) {
byte[] version = new byte[]{0x02, 0x01, 0x00};
byte[] algId = new byte[]{0x30, 0x0d, 0x06, 0x09, 0x2a, (byte) 0x86, 0x48, (byte) 0x86,
(byte) 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00};
byte[] octetString = concat(new byte[]{0x04}, derLength(pkcs1.length), pkcs1);
byte[] sequence = concat(version, algId, octetString);
return concat(new byte[]{0x30}, derLength(sequence.length), sequence);
}
private static String toCurl(String baseUrl, SignedRequest request) {
StringBuilder builder = new StringBuilder();
builder.append("curl --location '")
.append(baseUrl)
.append(request.path)
.append("' \\\n");
builder.append(" --request ").append(request.method).append(" \\\n");
for (Map.Entry<String, String> entry : request.headers.entrySet()) {
builder.append(" --header '")
.append(entry.getKey())
.append(": ")
.append(entry.getValue())
.append("' \\\n");
}
builder.append(" --data-raw '").append(request.body).append("'");
return builder.toString();
}
private static byte[] concat(byte[]... arrays) {
int totalLength = 0;
for (byte[] array : arrays) {
totalLength += array.length;
}
byte[] result = new byte[totalLength];
int offset = 0;
for (byte[] array : arrays) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
return result;
}
private static byte[] derLength(int length) {
if (length < 128) {
return new byte[]{(byte) length};
}
int temp = length;
int count = 0;
while (temp > 0) {
count++;
temp >>= 8;
}
byte[] result = new byte[1 + count];
result[0] = (byte) (0x80 | count);
for (int i = count; i > 0; i--) {
result[i] = (byte) (length & 0xFF);
length >>= 8;
}
return result;
}
private static class SignedRequest {
private final String method;
private final String path;
private final Map<String, String> headers;
private final String body;
private SignedRequest(String method, String path, Map<String, String> headers, String body) {
this.method = method;
this.path = path;
this.headers = headers;
this.body = body;
}
}
}
package com.pexx.core.utils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
/**
* @ClassName RefreshTokenTest
*/
public class RefreshTokenTest {
private static final String DEFAULT_BASE_URL = "http://qa.saas.pexx.com";
private static final String DEFAULT_REFRESH_TOKEN_PATH = "/apis/v1/refresh-token";
public static void main(String[] args) throws Exception {
// configuration (please modify according to actual situation)
String merchantCode = "your-merchant-code";
String apiKey = "your-api-key";
// Single-line Base64 PKCS#8 from merchant_private_key.txt. No PEM header, footer, or line breaks.
String privatekey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
String refreshToken = "your-refresh-token";
// Build call request body
String body = buildRefreshTokenBody(merchantCode,refreshToken);
// current time
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String nonce = UUID.randomUUID().toString().replace("-", "");
// Generate fields to be signed
String stringToSign = buildAccessTokenSignString(
"POST",
DEFAULT_REFRESH_TOKEN_PATH,
body,
apiKey,
merchantCode,
timestamp,
nonce
);
// generate signature
String signature = signRsa(privatekey, stringToSign);
Map<String, String> headers = new LinkedHashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("PexxApiKey", apiKey);
headers.put("X-TIMESTAMP", timestamp);
headers.put("X-NONCE", nonce);
headers.put("X-SIGNATURE", signature);
SignedRequest signedRequest = new SignedRequest("POST", DEFAULT_REFRESH_TOKEN_PATH, headers, body);
System.out.println("=== REFRESH TOKEN REQUEST ===");
System.out.println(toCurl(DEFAULT_BASE_URL, signedRequest));
}
private static String buildRefreshTokenBody(String merchantCode,String refreshToken) {
Map<String, Object> body = new LinkedHashMap<String, Object>();
body.put("merchantCode", merchantCode);
body.put("refreshToken", refreshToken);
return JSON.toJSONString(body);
}
public static String buildAccessTokenSignString(String method, String path, String body, String apiKey, String merchantCode,
String timestamp, String nonce) {
return String.format("%s:%s:%s:%s:%s:%s",
method.toUpperCase(),
path,
sha256Lower(minifyJson(body)),
apiKey,
merchantCode,
timestamp + ":" + nonce);
}
/**
* rsa sign
* @param privateKeyBase64
* @param stringToSign
* @return
* @throws Exception
*/
private static String signRsa(String privateKeyBase64, String stringToSign) throws Exception {
byte[] decoded = Base64.getDecoder().decode(privateKeyBase64);
PrivateKey privateKey = buildPrivateKey(decoded);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(stringToSign.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(signature.sign());
}
/**
* minify json
* @param body
* @return
*/
public static String minifyJson(String body) {
if (body == null || body.trim().isEmpty()) {
return "";
}
try {
Object parsed = JSON.parse(body);
if (!(parsed instanceof JSONObject)) {
return JSON.toJSONString(parsed);
}
JSONObject jsonObject = (JSONObject) parsed;
JSONObject sorted = new JSONObject();
jsonObject.keySet().stream().sorted().forEach(key -> sorted.put(key, jsonObject.get(key)));
return JSON.toJSONString(sorted, JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteBigDecimalAsPlain);
} catch (Exception e) {
return body.trim();
}
}
public static String sha256Lower(String input) {
return DigestUtils.sha256Hex(input == null ? "" : input).toLowerCase();
}
private static PrivateKey buildPrivateKey(byte[] keyBytes) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
try {
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
} catch (Exception ex) {
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(wrapPkcs1ToPkcs8(keyBytes)));
}
}
private static byte[] wrapPkcs1ToPkcs8(byte[] pkcs1) {
byte[] version = new byte[]{0x02, 0x01, 0x00};
byte[] algId = new byte[]{0x30, 0x0d, 0x06, 0x09, 0x2a, (byte) 0x86, 0x48, (byte) 0x86,
(byte) 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00};
byte[] octetString = concat(new byte[]{0x04}, derLength(pkcs1.length), pkcs1);
byte[] sequence = concat(version, algId, octetString);
return concat(new byte[]{0x30}, derLength(sequence.length), sequence);
}
private static String toCurl(String baseUrl, SignedRequest request) {
StringBuilder builder = new StringBuilder();
builder.append("curl --location '")
.append(baseUrl)
.append(request.path)
.append("' \\\n");
builder.append(" --request ").append(request.method).append(" \\\n");
for (Map.Entry<String, String> entry : request.headers.entrySet()) {
builder.append(" --header '")
.append(entry.getKey())
.append(": ")
.append(entry.getValue())
.append("' \\\n");
}
builder.append(" --data-raw '").append(request.body).append("'");
return builder.toString();
}
private static byte[] concat(byte[]... arrays) {
int totalLength = 0;
for (byte[] array : arrays) {
totalLength += array.length;
}
byte[] result = new byte[totalLength];
int offset = 0;
for (byte[] array : arrays) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
return result;
}
private static byte[] derLength(int length) {
if (length < 128) {
return new byte[]{(byte) length};
}
int temp = length;
int count = 0;
while (temp > 0) {
count++;
temp >>= 8;
}
byte[] result = new byte[1 + count];
result[0] = (byte) (0x80 | count);
for (int i = count; i > 0; i--) {
result[i] = (byte) (length & 0xFF);
length >>= 8;
}
return result;
}
private static class SignedRequest {
private final String method;
private final String path;
private final Map<String, String> headers;
private final String body;
private SignedRequest(String method, String path, Map<String, String> headers, String body) {
this.method = method;
this.path = path;
this.headers = headers;
this.body = body;
}
}
}
2. Signature for Business API Requests ( X-SIGNATURE, required )
Applicable APIs:
- All other
/apis/v1/**business APIs except/apis/v1/access-tokenand/apis/v1/refresh-token - File uploading related APIs will not use signature. (upload-files and bind-payout-files)
Signature algorithm:
HmacSHA512
String to sign:
METHOD:path:accessToken:sha256(minifyJson(body)):timestamp:nonceExample:
POST:/apis/v1/user/balance/list:your-access-token:sha256(minifyJson(body)):1714291200:6f2e7c1a4d9b4c2f9c7d1e3a5b6f8a0cNotes:
- The
secretKeyreturned by/apis/v1/access-tokenis the HMAC key - The
accessTokencarried inPexxAuthorizationmust match theaccessTokenused in the string to sign - An empty request body participates in signing as an empty string
3. Merchant Signature for Business API Requests ( X-MERCHANT-SIGNATURE, Optional )
This signature proves that the request was signed with the merchant's own RSA private key. X-SIGNATURE is still required and is still verified with secretKey. X-MERCHANT-SIGNATURE is an additional signature on the same request.
Pexx enables this verification per merchant. If it is not enabled for your merchant, do not send X-MERCHANT-SIGNATURE. Sending it has no effect.
Applicable APIs:
- The same business APIs that require
X-SIGNATURE - Not applicable to
POST /apis/v1/access-tokenorPOST /apis/v1/refresh-token. Those requests are already signed with RSA inX-SIGNATURE - Not applicable to file uploading APIs (upload-files and bind-payout-files)
Signature algorithm:
SHA256withRSA- Sign with the RSA private key that corresponds to the public key you provided to Pexx during onboarding
String to sign:
METHOD:path:accessToken:sha256(minifyJson(body)):timestamp:nonceThis is the same string used to generate X-SIGNATURE for a business API request. Build it once, then:
- Sign it with
secretKeyusingHmacSHA512, Base64-encode the result, and send it inX-SIGNATURE. - Sign the same string with your RSA private key using
SHA256withRSA, Base64-encode the result, and send it inX-MERCHANT-SIGNATURE.
Example:
POST:/apis/v1/user/balance/list:your-access-token:sha256(minifyJson(body)):1714291200:6f2e7c1a4d9b4c2f9c7d1e3a5b6f8a0cNotes:
METHOD,path,accessToken, body hashing,X-TIMESTAMP, andX-NONCEfollow the business API signing rules above- The
accessTokenin the string to sign is the raw token, without theBearerprefix. It must match the token inPexxAuthorization - An empty request body participates in signing as an empty string
- Use the same private key as the
access-tokenrequest: the single-line Base64 PKCS#8 string inmerchant_private_key.txt. - If the header is missing, the signature is invalid, or the signature does not match the registered public key, the request fails with the same authentication error as an invalid
X-SIGNATURE. Generate a newX-NONCEbefore retrying
String stringToSign = String.format("%s:%s:%s:%s:%s:%s",
method.toUpperCase(),
path,
accessToken,
sha256Lower(minifyJson(body)),
timestamp,
nonce);
String hmacSignature = signHmac(secretKey, stringToSign);
String merchantSignature = signRsa(privateKeyBase64, stringToSign);
headers.put("X-SIGNATURE", hmacSignature);
headers.put("X-MERCHANT-SIGNATURE", merchantSignature);signRsa, minifyJson, and sha256Lower are the same helpers used for the access-token request. signHmac is HmacSHA512 over the UTF-8 string to sign, with the raw HMAC bytes Base64-encoded.
API Specifications
1. POST /apis/v1/access-token
POST /apis/v1/access-tokenPurpose:
- Request access credentials
Request body parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
merchantCode | Yes | string | Merchant identifier |
grantType | Yes | string | For the current integration, client_credentials is recommended |
Response parameters:
| Parameter | Type | Description |
|---|---|---|
merchantCode | string | Merchant identifier |
businessUserId | string | The actual business user identifier for which the credentials are issued |
accessToken | string | Access token for business API calls |
refreshToken | string | Refresh token for renewing access credentials |
secretKey | string | Signing key for business API requests |
accessTokenExpiresIn | long | Remaining validity period of accessToken, in seconds |
refreshTokenExpiresIn | long | Remaining validity period of refreshToken, in seconds |
timestamp | long | Credential issuance time, Unix timestamp in seconds |
2. POST /apis/v1/refresh-token
POST /apis/v1/refresh-tokenPurpose:
- Refresh access credentials
Request body parameters:
| Parameter | Required | Type | Description |
|---|---|---|---|
merchantCode | Yes | string | Merchant identifier |
refreshToken | Yes | string | Refresh token for renewing access credentials |
Response parameters:
| Parameter | Type | Description |
|---|---|---|
merchantCode | string | Merchant identifier |
businessUserId | string | The actual business user identifier for which the credentials are issued |
accessToken | string | New access token for business API calls |
refreshToken | string | New refresh token for renewing access credentials |
secretKey | string | New signing key for business API requests |
accessTokenExpiresIn | long | Remaining validity period of accessToken, in seconds |
refreshTokenExpiresIn | long | Remaining validity period of refreshToken, in seconds |
timestamp | long | Credential issuance time, Unix timestamp in seconds |
3. General Requirements for Business APIs
Purpose:
- Use the access credentials to call specific business APIs
General requirements:
PexxAuthorization: Bearer {accessToken}must be included in the request header- The request must generate
X-SIGNATUREaccording to the business API signing rules except file uploading related APIs (upload-files and bind-payout-files) - When merchant signature verification is enabled for your merchant, the request must also include X-MERCHANT-SIGNATURE, generated from the same string to sign as X-SIGNATURE.
- The request and response parameters of each specific business API are subject to its corresponding API documentation
Authentication Failure Response
Response Structure
When authentication fails, the response body uses the following common fields:
| Field | Description |
|---|---|
code | Response code |
msg | Error description |
data | Business data; usually empty on failure |
Error Codes
| Type | Value | Description |
|---|---|---|
| HTTP status code | 401 | Returned when required headers are missing, the signature is invalid, the token is invalid, or authentication fails |
| Business error code | 1004 | INVALID_ACCESS, invalid access, for example merchant mismatch or invalid credentials |
| Business error code | 1009 | ACCESS_TOKEN_EXPIRED, accessToken has expired |
| Business error code | 1010 | REFRESH_TOKEN_EXPIRED, refreshToken has expired |
Updated 1 day ago