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 Type | Format | Used For | Example |
|---|---|---|---|
| Branch UUID | UUID v4 (36 chars) | /verify/bank, /verify/truewallet, /info | a1b2c3d4-e5f6-7890-abcd-ef1234567890 |
| B2B Client Key | 64-character hex | /b2b/* management endpoints | abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 |
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 asX-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
- Log in to the EasySlip Developer Portal
- Navigate to your application settings
- Generate a B2B API Key and Secret Key pair
- Note your branch UUID(s) from the branch settings
- 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:
| Header | Format | Description |
|---|---|---|
X-API-Key | string | Branch UUID or B2B Client hex key (see Two Key Types) |
X-Timestamp | string | Unix timestamp in seconds |
X-Nonce | string | UUID v4, unique per request |
X-Signature | string | HMAC-SHA256 hex signature |
Signature Computation
String-to-Sign Format
{METHOD}\n{PATH}\n{TIMESTAMP}\n{NONCE}\n{BODY_SHA256}| Component | Description |
|---|---|
METHOD | HTTP method in uppercase (GET, POST, PATCH, PUT, DELETE) |
PATH | Request path including leading slash (e.g., /b2b/branches) |
TIMESTAMP | Same value as the X-Timestamp header |
NONCE | Same value as the X-Nonce header |
BODY_SHA256 | SHA-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)
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)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
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']);#!/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)
// 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)# 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'])// 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']);#!/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:
| Permission | Description |
|---|---|
branch:read | List and view branches |
branch:write | Create, update, and delete branches |
quota:read | View quota information |
quota:write | Set, adjust, and reset quotas |
bank-account:read | List bank accounts linked to branches |
bank-account:write | Create, 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.