Singapay Home Page
Logo Icon
  1. Security
  2. Get Access Token v1.1

Information

MethodPathFormatAuthentication
POST/api/v1.1/access-token/b2bjsonHMAC SHA512 Signature

Request Details

When making a request to obtain an access token using the Get Access Token endpoint, several key pieces of information are required. These details are crucial for successful authentication and access to the API resources.

Headers Structure

FieldValueTypeMandatoryLengthDescriptionExample
X-PARTNER-IDAlphanumericMandatory-api_key (please check in merchant dashboard)b3ed7d4b-a96c-6c08-b3c7-12c3124242d9
X-CLIENT-IDAlphanumericMandatory-client_id (please check in merchant dashboard)123e4567-e89b-12d3-a456-426614174000
X-SignatureAlphanumericMandatory-HMAC SHA512 signature using client_secret as the key (please read How to generate Signature section)
Acceptapplication/jsonAlphabeticMandatory-Give back response with JSON format
Content-Typeapplication/jsonAlphabeticMandatory-Specify request body format as JSON

Body Structure

FieldValueTypeMandatoryLengthDescriptionExample
grant_typeclient_credentialsAlphabeticMandatory---

Body Example

{
  "grant_type": "client_credentials"
}

How to Generate X-Signature

Overview

The X-Signature header is a security mechanism that validates the authenticity of your request. This signature is generated using HMAC SHA512 algorithm and must be included in every access token request for v1.1. If the signature is invalid or the timestamp is incorrect, the request will be rejected.

Signature Algorithm: HMAC SHA512

The signature is created by combining your credentials with the current date, then hashing it with your Client Secret.

Step-by-Step Guide

Step 1: Prepare Your Credentials

You need three values from your merchant dashboard:

  • Client ID (X-CLIENT-ID header)
  • Client Secret (used as HMAC secret key, never sent in request)
  • API Key (X-PARTNER-ID header)

Step 2: Generate Timestamp

Create a timestamp in YYYYMMDD format (8 digits, no separators) using the current date.

Important: The timestamp must match the server’s current date. If you use yesterday’s or tomorrow’s date, the signature will be invalid.

Format: YYYYMMDD
Example: 20250921 (September 21, 2025)

Step 3: Build the Payload String

Concatenate the values with underscore (_) as separator:

Payload = Client ID + "_" + Client Secret + "_" + Timestamp

Example:

Client ID     = a2fca1f4-92f0-474d-a6d5-d92ca830be79
Client Secret = UAkHVDuPSqHQI17ED9vDXNHq9o6MfcSZ
Timestamp     = 20250921

Payload = a2fca1f4-92f0-474d-a6d5-d92ca830be79_UAkHVDuPSqHQI17ED9vDXNHq9o6MfcSZ_20250921

Step 4: Generate HMAC SHA512 Signature

Use the Client Secret as the HMAC key and hash the payload string:

Signature = HMAC-SHA512(Payload, Client Secret)

Implementation Examples

PHP

<?php
// Your credentials from merchant dashboard
$clientId = 'a2fca1f4-92f0-474d-a6d5-d92ca830be79';
$clientSecret = 'UAkHVDuPSqHQI17ED9vDXNHq9o6MfcSZ';
$apiKey = 'b3ed7d4b-a96c-6c08-b3c7-12c3124242d9';

// Step 1: Generate timestamp (YYYYMMDD format)
$timestamp = date('Ymd'); // e.g., "20250921"

// Step 2: Build payload string
$payload = $clientId . '_' . $clientSecret . '_' . $timestamp;

// Step 3: Generate HMAC SHA512 signature
$signature = hash_hmac('sha512', $payload, $clientSecret);

// Step 4: Prepare headers
$headers = [
    'X-PARTNER-ID: ' . $apiKey,
    'X-CLIENT-ID: ' . $clientId,
    'X-Signature: ' . $signature,
    'Accept: application/json',
    'Content-Type: application/json'
];

// Step 5: Make request
$body = json_encode(['grant_type' => 'client_credentials']);

$ch = curl_init('https://api.example.com/api/v1.1/access-token/b2b');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
?>

Python

import hmac
import hashlib
from datetime import datetime
import requests
import json

# Your credentials from merchant dashboard
client_id = 'a2fca1f4-92f0-474d-a6d5-d92ca830be79'
client_secret = 'UAkHVDuPSqHQI17ED9vDXNHq9o6MfcSZ'
api_key = 'b3ed7d4b-a96c-6c08-b3c7-12c3124242d9'

# Step 1: Generate timestamp (YYYYMMDD format)
timestamp = datetime.now().strftime('%Y%m%d')  # e.g., "20250921"

# Step 2: Build payload string
payload = f"{client_id}_{client_secret}_{timestamp}"

# Step 3: Generate HMAC SHA512 signature
signature = hmac.new(
    client_secret.encode('utf-8'),
    payload.encode('utf-8'),
    hashlib.sha512
).hexdigest()

# Step 4: Prepare headers
headers = {
    'X-PARTNER-ID': api_key,
    'X-CLIENT-ID': client_id,
    'X-Signature': signature,
    'Accept': 'application/json',
    'Content-Type': 'application/json'
}

# Step 5: Make request
body = {'grant_type': 'client_credentials'}

response = requests.post(
    'https://api.example.com/api/v1.1/access-token/b2b',
    headers=headers,
    json=body
)

print(response.json())

JavaScript (Node.js)

const crypto = require('crypto');
const axios = require('axios');

// Your credentials from merchant dashboard
const clientId = 'a2fca1f4-92f0-474d-a6d5-d92ca830be79';
const clientSecret = 'UAkHVDuPSqHQI17ED9vDXNHq9o6MfcSZ';
const apiKey = 'b3ed7d4b-a96c-6c08-b3c7-12c3124242d9';

// Step 1: Generate timestamp (YYYYMMDD format)
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const timestamp = `${year}${month}${day}`; // e.g., "20250921"

// Step 2: Build payload string
const payload = `${clientId}_${clientSecret}_${timestamp}`;

// Step 3: Generate HMAC SHA512 signature
const signature = crypto
  .createHmac('sha512', clientSecret)
  .update(payload)
  .digest('hex');

// Step 4: Prepare headers
const headers = {
  'X-PARTNER-ID': apiKey,
  'X-CLIENT-ID': clientId,
  'X-Signature': signature,
  'Accept': 'application/json',
  'Content-Type': 'application/json'
};

// Step 5: Make request
const body = { grant_type: 'client_credentials' };

axios.post('https://api.example.com/api/v1.1/access-token/b2b', body, { headers })
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error.response.data);
  });

cURL (Bash)

#!/bin/bash

# Your credentials from merchant dashboard
CLIENT_ID="a2fca1f4-92f0-474d-a6d5-d92ca830be79"
CLIENT_SECRET="UAkHVDuPSqHQI17ED9vDXNHq9o6MfcSZ"
API_KEY="b3ed7d4b-a96c-6c08-b3c7-12c3124242d9"

# Step 1: Generate timestamp (YYYYMMDD format)
TIMESTAMP=$(date +%Y%m%d)  # e.g., "20250921"

# Step 2: Build payload string
PAYLOAD="${CLIENT_ID}_${CLIENT_SECRET}_${TIMESTAMP}"

# Step 3: Generate HMAC SHA512 signature
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha512 -hmac "$CLIENT_SECRET" | cut -d' ' -f2)

# Step 4: Make request
curl -X POST "https://api.example.com/api/v1.1/access-token/b2b" \
  -H "X-PARTNER-ID: $API_KEY" \
  -H "X-CLIENT-ID: $CLIENT_ID" \
  -H "X-Signature: $SIGNATURE" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials"
  }'

Important Notes

Best Practices

  • Use YYYYMMDD format: The timestamp must be exactly 8 digits (e.g., 20250921)
  • Current date only: Always use today’s date. Yesterday’s or tomorrow’s date will fail validation
  • Case sensitivity: The signature is case-sensitive. Use lowercase for the hex output
  • Character encoding: Use UTF-8 encoding for all strings
  • HMAC key: Always use client_secret as the HMAC key, NOT the api_key

Common Mistakes to Avoid

  • ❌ Using wrong date format (e.g., 2025-09-21 or 21/09/2025)
  • ❌ Using wrong separator (e.g., - or : instead of _)
  • ❌ Using API Key as HMAC key instead of Client Secret
  • ❌ Wrong order of values in payload (must be: ClientID_ClientSecret_Timestamp)
  • ❌ Using SHA256 instead of SHA512
  • ❌ Forgetting to include all three headers (X-PARTNER-ID, X-CLIENT-ID, X-Signature)
  • ❌ Using cached/old signature (signature changes daily)

Troubleshooting

If you receive “Invalid signature” error:

  1. Verify timestamp format: Must be YYYYMMDD (8 digits, no separators)
  2. Check date: Must be current date in server timezone
  3. Verify payload order: ClientID_ClientSecret_Timestamp (underscore separated)
  4. Confirm algorithm: Must use SHA512, not SHA256
  5. Check HMAC key: Must use Client Secret, not API Key
  6. Verify credentials: Ensure Client ID, Client Secret, and API Key are correct and match

Security Considerations

  • Never expose Client Secret: Keep it secure on your server. Never send it in headers or URL
  • Use HTTPS only: Always make requests over HTTPS to prevent man-in-the-middle attacks
  • Signature rotation: The signature automatically changes daily due to the timestamp
  • Constant-time comparison: The server uses hash_equals() to prevent timing attacks

Response Details

The response section provides details about the response received from the server after making a request to obtain an access token using the Get Access Token endpoint. It includes information such as the HTTP status code, headers, and the body of the response. Understanding the response is crucial for handling authentication errors, successful token retrieval, and accessing API resources securely.

Response Structure

FieldTypeMandatoryLengthDescriptionExample
statusNumericMandatory3HTTP Status Code200
successBooleanMandatory1Indicates if the request was successfultrue
dataObjectConditional-Contains additional data (if available)-
> access_tokenAlphanumericMandatory344JWT TokeneyJ0eXAiOiJKV1Qi{…}
> token_typeAlphabeticMandatory-Type of tokenBearer
> expires_inNumericMandatory-Session duration in seconds3600

Response Example

Success: Here’s an example of a successful response.

{
    "status": 200,
    "success": true,
    "data": {
        "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9{...}",
        "token_type": "Bearer",
        "expires_in": "3600"
    }
}

Error: Validation errors (422) - Missing or invalid parameters

{
  "status": 422,
  "success": false,
  "error": {
    "code": 422,
    "message": "Header parameter 'X-Signature' cannot be null"
  }
}
{
  "status": 422,
  "success": false,
  "error": {
    "code": 422,
    "message": "Header parameter 'X-PARTNER-ID' cannot be null"
  }
}
{
  "status": 422,
  "success": false,
  "error": {
    "code": 422,
    "message": "Header parameter 'X-CLIENT-ID' cannot be null"
  }
}
{
  "status": 422,
  "success": false,
  "error": {
    "code": 422,
    "message": "Request parameter 'grant_type' cannot be null"
  }
}
{
  "status": 422,
  "success": false,
  "error": {
    "code": 422,
    "message": "Request parameter 'grant_type' has invalid value"
  }
}

Error: Authentication failed (401) - Invalid credentials or signature

{
  "status": 401,
  "success": false,
  "error": {
    "code": 401,
    "message": "Invalid credentials"
  }
}
{
  "status": 401,
  "success": false,
  "error": {
    "code": 401,
    "message": "Invalid signature"
  }
}
{
  "status": 401,
  "success": false,
  "error": {
    "code": 401,
    "message": "Merchant not found"
  }
}