Skip to content

B2B Authentication

The EasySlip API uses HMAC-SHA256 signature-based authentication for both verification/info endpoints and B2B management endpoints. Every request must be signed with your secret key to ensure authenticity and integrity.

Two Key Types

The X-API-Key header accepts two key formats. The format determines which endpoints you can access:

Key TypeFormatUsed ForExample
Branch UUIDUUID v4 (36 chars)/verify/bank, /verify/truewallet, /infoa1b2c3d4-e5f6-7890-abcd-ef1234567890
B2B Client Key64-character hex/b2b/* management endpointsabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789

How it works

  • For verification/info endpoints: Use the branch UUID as X-API-Key. The server looks up the branch, finds the associated B2B client for the service, and uses the B2B client's secret to verify the HMAC signature. You only need the branch UUID and the service's secret key.
  • For management endpoints (/b2b/*): Use the B2B client 64-character hex key as X-API-Key. The server looks up the B2B client directly and verifies the HMAC signature.

In both cases, the same secret key (from the B2B client) is used to sign the request.

Getting Your Keys

  1. Log in to the EasySlip Developer Portal
  2. Navigate to your application settings
  3. Generate a B2B API Key and Secret Key pair
  4. Note your branch UUID(s) from the branch settings
  5. Store the Secret Key securely — it will only be shown once

DANGER

Never expose your Secret Key in client-side code, public repositories, or logs. The Secret Key should only be used in server-side applications.

Required Headers

Every API request must include these headers:

HeaderFormatDescription
X-API-KeystringBranch UUID or B2B Client hex key (see Two Key Types)
X-TimestampstringUnix timestamp in seconds
X-NoncestringUUID v4, unique per request
X-SignaturestringHMAC-SHA256 hex signature

Signature Computation

String-to-Sign Format

{METHOD}\n{PATH}\n{TIMESTAMP}\n{NONCE}\n{BODY_SHA256}
ComponentDescription
METHODHTTP method in uppercase (GET, POST, PATCH, PUT, DELETE)
PATHRequest path including leading slash (e.g., /b2b/branches)
TIMESTAMPSame value as the X-Timestamp header
NONCESame value as the X-Nonce header
BODY_SHA256SHA-256 hex digest of the request body

Body Hash

  • For requests with a body (POST, PUT, PATCH): compute SHA-256 of the raw JSON body string
  • For requests without a body (GET, DELETE): compute SHA-256 of an empty string ("")

TIP

SHA-256 of an empty string is always: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Signature

HMAC-SHA256(secretKey, stringToSign)

The result is a lowercase hex string.

Timestamp Tolerance

The server accepts timestamps within ±5 minutes of the current server time. Requests outside this window will be rejected with INVALID_TIMESTAMP.

Nonce Uniqueness

Each nonce must be a UUID v4 and must be unique. The server tracks recent nonces and will reject duplicates with DUPLICATE_NONCE. Generate a new UUID for every request.

Code Examples

Verify/Info Endpoints (Branch UUID)

javascript
import crypto from 'crypto'

function signRequest({ method, path, body, apiKey, secretKey }) {
    const timestamp = Math.floor(Date.now() / 1000).toString()
    const nonce = crypto.randomUUID()
    const bodyString = body ? JSON.stringify(body) : ''
    const bodyHash = crypto.createHash('sha256').update(bodyString).digest('hex')

    const stringToSign = `${method}\n${path}\n${timestamp}\n${nonce}\n${bodyHash}`
    const signature = crypto.createHmac('sha256', secretKey).update(stringToSign).digest('hex')

    return {
        'X-API-Key': apiKey,
        'X-Timestamp': timestamp,
        'X-Nonce': nonce,
        'X-Signature': signature,
        ...(body ? { 'Content-Type': 'application/json' } : {}),
    }
}

// Example: Get application info (using branch UUID)
const headers = signRequest({
    method: 'GET',
    path: '/info',
    body: null,
    apiKey: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', // Branch UUID
    secretKey: 'your_secret_key',
})

const response = await fetch('https://api.easyslip.com/v2/info', { headers })
const result = await response.json()
console.log(result.data)
python
import hashlib
import hmac
import json
import time
import uuid
import requests

def sign_request(method, path, body, api_key, secret_key):
    timestamp = str(int(time.time()))
    nonce = str(uuid.uuid4())
    body_string = json.dumps(body, separators=(',', ':')) if body else ''
    body_hash = hashlib.sha256(body_string.encode()).hexdigest()

    string_to_sign = f'{method}\n{path}\n{timestamp}\n{nonce}\n{body_hash}'
    signature = hmac.new(
        secret_key.encode(),
        string_to_sign.encode(),
        hashlib.sha256
    ).hexdigest()

    return {
        'X-API-Key': api_key,
        'X-Timestamp': timestamp,
        'X-Nonce': nonce,
        'X-Signature': signature,
    }

# Example: Get application info (using branch UUID)
headers = sign_request(
    method='GET',
    path='/info',
    body=None,
    api_key='a1b2c3d4-e5f6-7890-abcd-ef1234567890',  # Branch UUID
    secret_key='your_secret_key',
)

response = requests.get('https://api.easyslip.com/v2/info', headers=headers)
result = response.json()
print(result['data'])
php
<?php

function signRequest(string $method, string $path, ?array $body, string $apiKey, string $secretKey): array
{
    $timestamp = (string) time();
    $nonce = sprintf(
        '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
        mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
        mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
    );
    $bodyString = $body ? json_encode($body, JSON_UNESCAPED_UNICODE) : '';
    $bodyHash = hash('sha256', $bodyString);

    $stringToSign = implode("\n", [$method, $path, $timestamp, $nonce, $bodyHash]);
    $signature = hash_hmac('sha256', $stringToSign, $secretKey);

    return [
        'X-API-Key' => $apiKey,
        'X-Timestamp' => $timestamp,
        'X-Nonce' => $nonce,
        'X-Signature' => $signature,
    ];
}

// Example: Get application info (using branch UUID)
$headers = signRequest('GET', '/info', null, 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'your_secret_key');

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api.easyslip.com/v2/info',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => array_map(
        fn($k, $v) => "$k: $v",
        array_keys($headers),
        array_values($headers)
    ),
]);

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

$result = json_decode($response, true);
print_r($result['data']);
bash
#!/bin/bash
# Branch UUID for verify/info endpoints
API_KEY="a1b2c3d4-e5f6-7890-abcd-ef1234567890"
SECRET_KEY="your_secret_key"
METHOD="GET"
PATH_URL="/info"
TIMESTAMP=$(date +%s)
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')

# For GET/DELETE requests, hash empty string
BODY_HASH=$(printf '' | shasum -a 256 | cut -d' ' -f1)

STRING_TO_SIGN="${METHOD}\n${PATH_URL}\n${TIMESTAMP}\n${NONCE}\n${BODY_HASH}"
SIGNATURE=$(printf "${STRING_TO_SIGN}" | openssl dgst -sha256 -hmac "${SECRET_KEY}" | cut -d' ' -f2)

curl -X GET "https://api.easyslip.com/v2${PATH_URL}" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Signature: ${SIGNATURE}"

Management Endpoints (B2B Client Key)

javascript
// Example: List branches (using B2B client 64-char hex key)
const headers = signRequest({
    method: 'GET',
    path: '/b2b/branches',
    body: null,
    apiKey: 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789', // B2B Client key
    secretKey: 'your_secret_key',
})

const response = await fetch('https://api.easyslip.com/b2b/branches', { headers })
const result = await response.json()
console.log(result.data)
python
# Example: List branches (using B2B client 64-char hex key)
headers = sign_request(
    method='GET',
    path='/b2b/branches',
    body=None,
    api_key='abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789',  # B2B Client key
    secret_key='your_secret_key',
)

response = requests.get('https://api.easyslip.com/b2b/branches', headers=headers)
result = response.json()
print(result['data'])
php
// Example: List branches (using B2B client 64-char hex key)
$headers = signRequest(
    'GET',
    '/b2b/branches',
    null,
    'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789', // B2B Client key
    'your_secret_key'
);

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api.easyslip.com/b2b/branches',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => array_map(
        fn($k, $v) => "$k: $v",
        array_keys($headers),
        array_values($headers)
    ),
]);

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

$result = json_decode($response, true);
print_r($result['data']);
bash
#!/bin/bash
# B2B Client 64-char hex key for management endpoints
API_KEY="abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
SECRET_KEY="your_secret_key"
METHOD="GET"
PATH_URL="/b2b/branches"
TIMESTAMP=$(date +%s)
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')

# For GET/DELETE requests, hash empty string
BODY_HASH=$(printf '' | shasum -a 256 | cut -d' ' -f1)

STRING_TO_SIGN="${METHOD}\n${PATH_URL}\n${TIMESTAMP}\n${NONCE}\n${BODY_HASH}"
SIGNATURE=$(printf "${STRING_TO_SIGN}" | openssl dgst -sha256 -hmac "${SECRET_KEY}" | cut -d' ' -f2)

curl -X GET "https://api.easyslip.com${PATH_URL}" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Signature: ${SIGNATURE}"

Permissions

Each B2B API key has a set of permissions that control which operations it can perform:

PermissionDescription
branch:readList and view branches
branch:writeCreate, update, and delete branches
quota:readView quota information
quota:writeSet, adjust, and reset quotas
bank-account:readList bank accounts linked to branches
bank-account:writeCreate, link, and unlink bank accounts

WARNING

If your API key does not have the required permission for an endpoint, the request will be rejected with a 403 Forbidden response.

Bank Slip Verification API for Thai Banking