Skip to content

การยืนยันตัวตน ​

EasySlip API ใช้ HMAC-SHA256 Signature Authentication เพื่อความปลอดภัยในการเข้าถึง API ทุก request ต้องลงนามด้วย Secret Key เพื่อรับรองความถูกต้องและความสมบูรณ์ของข้อมูล

Credentials ที่ต้องใช้ ​

เมื่อสร้างแอปพลิเคชัน คุณจะได้รับ credentials 3 ตัว:

Credentialรูปแบบหน้าที่ได้มาจากไหน
Partners API Keyhex 64 ตัวอักษรระบุตัวตน ส่งเป็น X-API-Key ในทุก requestสร้างในหน้าตั้งค่าแอปพลิเคชัน
Secret Keyhex 64 ตัวอักษรใช้ลงนาม (sign) ทุก request ด้วย HMAC-SHA256แสดงครั้งเดียวตอนสร้าง Partners Client
Branch KeyUUID v4ระบุ Branch ส่งเป็น X-Branch-Key สำหรับ endpoint ที่ต้องระบุสาขาสร้างอัตโนมัติเมื่อสร้าง Branch ใหม่

สรุปง่ายๆ

  • ทุก request → ส่ง Partners API Key เป็น X-API-Key แล้ว sign ด้วย Secret Key
  • ตรวจสอบสลิป / จัดการสาขาเฉพาะ? → ส่ง Branch Key เป็น X-Branch-Key เพิ่ม

DANGER

อย่าเปิดเผย Secret Key ในโค้ดฝั่ง client, repository สาธารณะ หรือ logs Secret Key ควรใช้ในแอปพลิเคชันฝั่ง server เท่านั้น

การรับ API Key ​

  1. เข้าสู่ระบบ EasySlip Developer Portal
  2. ไปที่การตั้งค่าแอปพลิเคชัน
  3. สร้างคู่ Partners API Key และ Secret Key
  4. จดบันทึก Branch Key (UUID) จากการตั้งค่าสาขา
  5. เก็บ Secret Key ไว้อย่างปลอดภัย — จะแสดงให้เห็นเพียงครั้งเดียว

Diagram ​

┌──────────────────────────────────────────────────────┐
│                    Application                        │
│                                                       │
│   ┌──────────────────────────────────────────────┐   │
│   │              Partners Client                      │   │
│   │   Partners API Key  ──→ X-API-Key (ทุก request)  │   │
│   │   Secret Key   ──→ ลงนามทุก request         │   │
│   └──────────────────────────────────────────────┘   │
│                                                       │
│   ┌───────────────┐  ┌───────────────┐               │
│   │   Branch A    │  │   Branch B    │  ...          │
│   │   Branch Key  │  │   Branch Key  │               │
│   │ ──→ X-Branch- │  │ ──→ X-Branch- │               │
│   │     Key       │  │     Key       │               │
│   └───────────────┘  └───────────────┘               │
└──────────────────────────────────────────────────────┘

วิธีเลือก Header ที่จะส่ง ​

X-API-Key ส่ง Partners API Key เสมอ ส่วน X-Branch-Key ส่งเฉพาะ endpoint ที่ต้องระบุสาขา:

ต้องการทำอะไรX-API-KeyX-Branch-KeyEndpoint
ตรวจสอบสลิป/ดูข้อมูลPartners API Key (hex 64)Branch Key (UUID)/verify/bank, /verify/truewallet, /info
จัดการสาขาเฉพาะ/โควตา/บัญชีธนาคารPartners API Key (hex 64)Branch Key (UUID)/b2b/branch, /b2b/branch/*
ดูรายการสาขา/สร้างสาขา/สร้างบัญชีธนาคารPartners API Key (hex 64)ไม่ต้องส่ง/b2b/branches, /b2b/bank-accounts

Headers ที่จำเป็น ​

Headerรูปแบบคำอธิบาย
X-API-KeystringPartners API Key (hex 64) — ส่งทุก request
X-Branch-KeystringBranch Key (UUID) — ส่งเมื่อ endpoint ต้องระบุสาขา
X-TimestampstringUnix timestamp เป็นวินาที
X-NoncestringUUID v4 ไม่ซ้ำกันในแต่ละ request
X-SignaturestringHMAC-SHA256 hex signature

การคำนวณ Signature ​

ขั้นตอนที่ 1: สร้าง String-to-Sign ​

{METHOD}\n{PATH}\n{TIMESTAMP}\n{NONCE}\n{BODY_SHA256}
ส่วนประกอบคำอธิบาย
METHODHTTP method ตัวพิมพ์ใหญ่ (GET, POST, PATCH, PUT, DELETE)
PATHเส้นทาง request รวมเครื่องหมาย / นำหน้า (เช่น /b2b/branches)
TIMESTAMPค่าเดียวกับ header X-Timestamp
NONCEค่าเดียวกับ header X-Nonce
BODY_SHA256SHA-256 hex digest ของ request body

ขั้นตอนที่ 2: คำนวณ Body Hash ​

  • สำหรับ request ที่มี body (POST, PUT, PATCH): คำนวณ SHA-256 ของ raw JSON body string
  • สำหรับ request ที่ไม่มี body (GET, DELETE): คำนวณ SHA-256 ของ empty string ("")

TIP

SHA-256 ของ empty string จะเป็นค่าคงที่: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

ขั้นตอนที่ 3: ลงนามด้วย HMAC-SHA256 ​

HMAC-SHA256(secretKey, stringToSign)

ผลลัพธ์เป็น lowercase hex string

ค่าเผื่อ Timestamp ​

เซิร์ฟเวอร์ยอมรับ timestamp ภายใน ±5 นาที จากเวลาปัจจุบันของเซิร์ฟเวอร์ request ที่อยู่นอกช่วงนี้จะถูกปฏิเสธด้วย INVALID_TIMESTAMP

ความเป็นเอกลักษณ์ของ Nonce ​

แต่ละ nonce ต้องเป็น UUID v4 และต้องไม่ซ้ำกัน เซิร์ฟเวอร์จะติดตาม nonce ล่าสุดและจะปฏิเสธ nonce ที่ซ้ำด้วย DUPLICATE_NONCE ต้องสร้าง UUID ใหม่สำหรับทุก request

ตัวอย่างโค้ด ​

ฟังก์ชัน signRequest (ใช้ได้กับทุก endpoint) ​

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' } : {}),
    }
}
python
import hashlib
import hmac
import json
import time
import uuid

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,
    }
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,
    ];
}
bash
#!/bin/bash
API_KEY="your_partners_api_key"
SECRET_KEY="your_secret_key"
METHOD="GET"
PATH_URL="/info"
TIMESTAMP=$(date +%s)
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')

# สำหรับ GET/DELETE ให้ 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)

ตัวอย่าง: ตรวจสอบสลิป (ต้องส่ง X-Branch-Key) ​

javascript
const PARTNERS_API_KEY = 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789'
const SECRET_KEY = 'your_secret_key'
const BRANCH_KEY = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'

const body = { payload: '00020101021230...' }
const headers = signRequest({
    method: 'POST',
    path: '/verify/bank',
    body,
    apiKey: PARTNERS_API_KEY,
    secretKey: SECRET_KEY,
})

const response = await fetch('https://api-partners.easyslip.com/v2/verify/bank', {
    method: 'POST',
    headers: { ...headers, 'X-Branch-Key': BRANCH_KEY },
    body: JSON.stringify(body),
})
const result = await response.json()
console.log(result.data)
python
import requests

PARTNERS_API_KEY = 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789'
SECRET_KEY = 'your_secret_key'
BRANCH_KEY = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'

body = {'payload': '00020101021230...'}
headers = sign_request('POST', '/verify/bank', body, PARTNERS_API_KEY, SECRET_KEY)
headers['X-Branch-Key'] = BRANCH_KEY
headers['Content-Type'] = 'application/json'

response = requests.post(
    'https://api-partners.easyslip.com/v2/verify/bank',
    headers=headers,
    json=body,
)
result = response.json()
print(result['data'])
php
$partnersApiKey = 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';
$secretKey = 'your_secret_key';
$branchKey = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';

$body = ['payload' => '00020101021230...'];
$headers = signRequest('POST', '/verify/bank', $body, $partnersApiKey, $secretKey);
$headers['X-Branch-Key'] = $branchKey;

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api-partners.easyslip.com/v2/verify/bank',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => array_merge(
        array_map(fn($k, $v) => "$k: $v", array_keys($headers), array_values($headers)),
        ['Content-Type: application/json']
    ),
    CURLOPT_POSTFIELDS => json_encode($body),
]);
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
print_r($result['data']);
bash
curl -X POST "https://api-partners.easyslip.com/v2/verify/bank" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Branch-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Signature: ${SIGNATURE}" \
  -H "Content-Type: application/json" \
  -d '{"payload": "00020101021230..."}'

ตัวอย่าง: ดูรายการสาขา (ไม่ต้องส่ง X-Branch-Key) ​

javascript
const headers = signRequest({
    method: 'GET',
    path: '/b2b/branches',
    body: null,
    apiKey: PARTNERS_API_KEY,
    secretKey: SECRET_KEY,
})

const response = await fetch('https://api-partners.easyslip.com/v2/b2b/branches', { headers })
const result = await response.json()
console.log(result.data)
python
headers = sign_request('GET', '/b2b/branches', None, PARTNERS_API_KEY, SECRET_KEY)

response = requests.get('https://api-partners.easyslip.com/v2/b2b/branches', headers=headers)
result = response.json()
print(result['data'])
php
$headers = signRequest('GET', '/b2b/branches', null, $partnersApiKey, $secretKey);

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api-partners.easyslip.com/v2/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
curl -X GET "https://api-partners.easyslip.com/v2/b2b/branches" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Signature: ${SIGNATURE}"

ตัวอย่าง: ดูโควต้าสาขา (ต้องส่ง X-Branch-Key) ​

javascript
const headers = signRequest({
    method: 'GET',
    path: '/b2b/branch/quota',
    body: null,
    apiKey: PARTNERS_API_KEY,
    secretKey: SECRET_KEY,
})

const response = await fetch('https://api-partners.easyslip.com/v2/b2b/branch/quota', {
    headers: { ...headers, 'X-Branch-Key': BRANCH_KEY },
})
const result = await response.json()
console.log(result.data)
python
headers = sign_request('GET', '/b2b/branch/quota', None, PARTNERS_API_KEY, SECRET_KEY)
headers['X-Branch-Key'] = BRANCH_KEY

response = requests.get('https://api-partners.easyslip.com/v2/b2b/branch/quota', headers=headers)
result = response.json()
print(result['data'])
php
$headers = signRequest('GET', '/b2b/branch/quota', null, $partnersApiKey, $secretKey);
$headers['X-Branch-Key'] = $branchKey;

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => 'https://api-partners.easyslip.com/v2/b2b/branch/quota',
    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
curl -X GET "https://api-partners.easyslip.com/v2/b2b/branch/quota" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Branch-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Signature: ${SIGNATURE}"

สิทธิ์การใช้งาน (Permissions) ​

แต่ละ Partners API key จะมีชุดสิทธิ์ที่กำหนดว่าสามารถทำอะไรได้บ้าง:

Permissionคำอธิบาย
branch:readดูรายการและข้อมูลสาขา
branch:writeสร้าง แก้ไข และลบสาขา
quota:readดูข้อมูลโควตา
quota:writeกำหนด ปรับ และรีเซ็ตโควตา
bank-account:readดูบัญชีธนาคารที่เชื่อมต่อกับสาขา
bank-account:writeสร้าง เชื่อมต่อ และยกเลิกการเชื่อมต่อบัญชีธนาคาร

WARNING

หาก API key ของคุณไม่มีสิทธิ์ที่จำเป็นสำหรับ endpoint นั้น request จะถูกปฏิเสธด้วย 403 Forbidden

แนวทางปฏิบัติด้านความปลอดภัย ​

1. อย่าเปิดเผย Key ในโค้ด Client-side ​

javascript
// ❌ ไม่ควรทำ
const API_KEY = 'your-api-key-here';

// ✅ ควรทำ - ใช้ Environment Variables
const API_KEY = process.env.EASYSLIP_API_KEY;

2. ใช้ Environment Variables ​

bash
EASYSLIP_PARTNERS_API_KEY=your-partners-api-key
EASYSLIP_SECRET_KEY=your-secret-key
EASYSLIP_BRANCH_KEY=your-branch-uuid
javascript
import 'dotenv/config';

const partnersApiKey = process.env.EASYSLIP_PARTNERS_API_KEY;
const secretKey = process.env.EASYSLIP_SECRET_KEY;
const branchKey = process.env.EASYSLIP_BRANCH_KEY;
php
$partnersApiKey = getenv('EASYSLIP_PARTNERS_API_KEY');
$secretKey = getenv('EASYSLIP_SECRET_KEY');
$branchKey = getenv('EASYSLIP_BRANCH_KEY');
python
import os

partners_api_key = os.environ.get('EASYSLIP_PARTNERS_API_KEY')
secret_key = os.environ.get('EASYSLIP_SECRET_KEY')
branch_key = os.environ.get('EASYSLIP_BRANCH_KEY')

3. ทำ Request จาก Server เท่านั้น ​

javascript
// ❌ ไม่ควรทำ - Client-side request เปิดเผย API key และ secret
fetch('https://api-partners.easyslip.com/v2/verify/bank', {
  headers: { 'X-API-Key': 'your-key', 'X-Signature': '...' }
});

// ✅ ควรทำ - Request ผ่าน Server ของคุณ
fetch('/api/verify-slip', {
  method: 'POST',
  body: JSON.stringify({ image: slipImage })
});

4. IP Whitelisting ​

ตั้งค่า IP Whitelist เพื่อจำกัดการเข้าถึง API เฉพาะ IP ที่กำหนด:

  1. ไปที่ ตั้งค่าแอปพลิเคชัน
  2. เพิ่ม IP Address ของ Server ลงใน Whitelist
  3. ใช้ * เพื่ออนุญาตทุก IP (ไม่แนะนำสำหรับ Production)

ข้อผิดพลาดการยืนยันตัวตน ​

Error CodeHTTP Statusคำอธิบายวิธีแก้ไข
INVALID_AUTH_HEADERS401Headers ไม่ถูกต้องหรือไม่ครบตรวจสอบว่าส่ง X-API-Key, X-Timestamp, X-Nonce, X-Signature ครบ
INVALID_API_KEY401API Key ไม่ถูกต้องตรวจสอบ Partners API Key
MISSING_BRANCH_KEY401ไม่ได้ส่ง X-Branch-Keyเพิ่ม header X-Branch-Key สำหรับ endpoint ที่ต้องระบุสาขา
INVALID_BRANCH_KEY401Branch Key ไม่ถูกต้องตรวจสอบ Branch Key (UUID)
INVALID_TIMESTAMP401Timestamp อยู่นอกช่วง ±5 นาทีตรวจสอบนาฬิกาเครื่อง
DUPLICATE_NONCE401Nonce ซ้ำสร้าง UUID ใหม่ทุก request
INVALID_SIGNATURE401Signature ไม่ตรงตรวจสอบ Secret Key และวิธีคำนวณ signature
SERVICE_SUSPENDED403แอปพลิเคชันถูกระงับติดต่อ Support
BRANCH_INACTIVE403Branch ถูกปิดใช้งานเปิดใช้งาน Branch ใหม่
IP_NOT_ALLOWED403IP ไม่อยู่ใน Whitelistเพิ่ม IP ลงใน Whitelist
BRANCH_QUOTA_EXCEEDED403เกินโควต้าสาขาอัพเกรดแพ็กเกจ หรือรอให้โควต้ารีเซ็ต
PERMISSION_DENIED403ไม่มีสิทธิ์เข้าถึงตรวจสอบ permissions ของ Partners Client

รองรับหลาย Branch ​

EasySlip รองรับหลาย Branch ต่อแอปพลิเคชัน แต่ละ Branch มี Branch Key แยกกัน:

  • Main Branch: Branch Key หลัก มีโควต้าเต็ม
  • Sub-Branches: Branch Key เพิ่มเติม มีการติดตามโควต้าแยก

ช่วยให้คุณ:

  • ติดตามการใช้งานต่อจุดเชื่อมต่อ
  • กำหนด IP Restrictions ที่ต่างกันต่อ Branch
  • จัดการการจัดสรรโควต้าระหว่างทีม

ขั้นตอนถัดไป ​

Bank Slip Verification API for Thai Banking