CCP Gateway

Dashboard Overview

Real-time netting positions and prepaid gas status.

Offline
--:--:--

Available Gas

Prepaid settlement buffer

0.00

Reserved Gas

Locked deposit coverage

0.00

Credit Balance

Settlement collateral

0.00

Reserved Credit

Hold for cross-merchant swaps

0.00

CCP Net Positions

Central Counterparty (CCP) netting ledger. System-wide net positions must sum to 0.00.
Merchant Net Position (PTS)

Settlement Agents

Registered agents receiving commission per matched order.

P2P Matching & Escrow Board

Tx ID Merchant Customer (Grade) Type Amount Status Match ID Expires In Actions / Audit

Audit Options

Zero-Discrepancy Formula Audit
User Net Flow (D - W) 0.00
=
Asset Change (Gas + Credit) 0.00
+
Commissions / Fees 0.00
Audit Status
BALANCED
LHS: 0.00 = RHS: 0.00

Gateway Volume & Status Distribution

Transaction Volume (P2P vs Direct Fallback)

Transaction Status Distribution

Merchant Collateral & Netting Status

Security Audit Logs (บันทึกกิจกรรมระบบ)

Detailed audit trail of all security changes, key rotations, and administrative mutations made in the system.
Log ID Actor Type Actor ID Actor Name Action IP Address Timestamp Details (Metadata)
No audit logs found.

Activity Logs (บันทึกกิจกรรมบัญชีร้านค้า)

ประวัติการทำกิจกรรม ล็อกอิน เปลี่ยนแปลงบัญชีธนาคาร หมุนเวียนคีย์ความปลอดภัย และการอัปเดตสิทธิ์บนบัญชีร้านค้าของคุณ
Log ID Action IP Address Timestamp Details (รายละเอียด)
No activity logs found.

Request Simulator

Sandbox HTTP Console Logs

[System] Sandbox initialized. Access portal as a merchant and trigger requests to simulate API payloads.

Disputed Transactions Box

0 ACTIVE
When disputes occur, transactions are paused in the timeout queue. Admin review and override is required.

Pending Dispute Proposals (Maker-Checker)

0 PENDING
Transactions ≥ 50,000 PTS require double administrator authorization. One admin proposes, and a different admin must approve.

Admin Override Action History

Tx ID Admin Action Reason Timestamp

API Docs Index

1. Authentication

All partner API requests sent to the P2P gateway must include your merchant specific API Key in the HTTP headers. Keep this key secure and do not share it.

Request Header
X-API-Key: key-lucky-games

2. Flow A: Deposit Request (Cash-In)

Creates a deposit order. The gateway immediately locks the requested amount of gas from your gas_balance to cover potential netting fallbacks.

POST
http://localhost:3005/api/v1/deposit
Request Payload (JSON)
{
  "merchantUserId": "user_a1",
  "amount": "100.0000",
  "idempotencyKey": "ik_1781294819"
}
Success Response (200 OK)
{
  "id": 142,
  "merchantId": 1,
  "userId": 1,
  "type": "DEPOSIT",
  "amount": "100.0000",
  "status": "PENDING_MATCH",
  "idempotencyKey": "ik_1781294819",
  "createdAt": "2026-06-13T10:00:00.000Z"
}

3. Flow B: Withdraw Request (Cash-Out)

Creates a withdrawal order. No gas is reserved. Withdrawals are queued and matched against deposit orders of the same amount.

POST
http://localhost:3005/api/v1/withdraw
Request Payload (JSON)
{
  "merchantUserId": "user_b1",
  "amount": "100.0000",
  "idempotencyKey": "ik_901847192"
}

4. P2P Escrow Action Signalling

Once orders are matched, customers interact directly to transfer cash. Partners signal transaction status updates to the gateway.

A. Mark Transferred (Paid)

The depositor signals that cash has been transferred to the withdrawer's bank account.

POST
/api/transaction/:id/transferred

B. Confirm & Release

The withdrawer verifies receipt of the funds and releases the escrow credit balance.

POST
/api/transaction/:id/release

C. File Dispute

If funds do not arrive, the withdrawer opens a dispute, pausing timeout expiration.

POST
/api/transaction/:id/dispute
{
  "reason": "Customer uploaded fake slip"
}

5. Webhook Callback Event Structure

The gateway posts webhook updates to your registered webhookUrl when transaction states transition.

Callback Payload (JSON)
{
  "event": "transaction.updated",
  "timestamp": "2026-06-13T10:15:00.000Z",
  "data": {
    "txId": 142,
    "merchantId": 1,
    "type": "DEPOSIT",
    "amount": "100.0000",
    "status": "COMPLETED",
    "idempotencyKey": "ik_1781294819"
  }
}

5.1 Webhook Signature Verification (การตรวจสอบความถูกต้องลายเซ็น)

เพื่อความปลอดภัยสูงสุด ร้านค้าควรอ่านและตรวจสอบลายเซ็นที่ส่งมาใน Header X-Webhook-Signature ทุกครั้ง เพื่อป้องกันการปลอมแปลงคำขอโอนเงินจากบุคคลภายนอก ลายเซ็นนี้คำนวณจาก **HMAC-SHA256** โดยใช้ raw body ของ webhook payload ร่วมกับ Webhook Secret ของร้านค้า

Code Verification Snippets
Node.js (Express)
const crypto = require('crypto');

app.post('/api/callback', (req, res) => {
  const signatureHeader = req.headers['x-webhook-signature'];
  const webhookSecret = 'your_whsec_secret_here'; // ดูได้ที่หน้า Settings
  
  // คำนวณ Signature จาก Raw Body
  const rawBody = JSON.stringify(req.body);
  const calculatedSignature = crypto
    .createHmac('sha256', webhookSecret)
    .update(rawBody)
    .digest('hex');

  if (calculatedSignature === signatureHeader) {
    console.log('Webhook signature valid!');
    return res.status(200).send('success');
  } else {
    console.error('Invalid signature!');
    return res.status(401).send('Unauthorized');
  }
});
PHP
<?php
$signatureHeader = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$webhookSecret = 'your_whsec_secret_here';

// รับ Raw Request Body
$rawBody = file_get_contents('php://input');
$calculatedSignature = hash_hmac('sha256', $rawBody, $webhookSecret);

if (hash_equals($calculatedSignature, $signatureHeader)) {
    echo "Webhook signature valid!";
    http_response_code(200);
} else {
    echo "Invalid signature!";
    http_response_code(401);
}
?>
Python (Flask)
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)

@app.route('/api/callback', methods=['POST'])
def webhook_callback():
    signature_header = request.headers.get('X-Webhook-Signature')
    webhook_secret = b'your_whsec_secret_here'
    
    # คำนวณ Signature จาก Raw Data
    raw_body = request.get_data()
    calculated_signature = hmac.new(
        webhook_secret,
        raw_body,
        hashlib.sha256
    ).hexdigest()

    if hmac.compare_digest(calculated_signature, signature_header):
        print("Webhook signature valid!")
        return "success", 200
    else:
        print("Invalid signature!")
        abort(401)

5.2 Webhook Payload Decryption (การถอดรหัสข้อมูล Webhook)

หากร้านค้าเปิดใช้งาน Webhook Payload Encryption ในหน้าการตั้งค่า ข้อมูลดิบ (raw body) ของ Webhook จะถูกเข้ารหัสเพื่อความปลอดภัยระดับสูงโดยใช้ AES-256-GCM ข้อมูลจะจัดส่งมาในรูปแบบ JSON ดังนี้:

{
  "ciphertext": "<hex_encoded_encrypted_data>",
  "iv": "<hex_encoded_initialization_vector_12_bytes>",
  "tag": "<hex_encoded_authentication_tag_16_bytes>"
}

ในการถอดรหัส ร้านค้าต้องใช้ Webhook Secret เพื่อนำมาหาค่าแฮช SHA-256 (32 ไบต์) สำหรับใช้เป็นคีย์สมมาตรหลักในการถอดรหัส AES-256-GCM:

Code Decryption Snippets
Node.js
const crypto = require('crypto');

function decryptWebhookPayload(encryptedPayload, webhookSecret) {
  const { ciphertext, iv, tag } = encryptedPayload;
  
  // 1. Derive the 32-byte key via SHA-256 hash of the webhook secret
  const key = crypto.createHash('sha256').update(webhookSecret).digest();
  
  // 2. Setup decipher using AES-256-GCM
  const decipher = crypto.createDecipheriv(
    'aes-256-gcm',
    key,
    Buffer.from(iv, 'hex')
  );
  
  decipher.setAuthTag(Buffer.from(tag, 'hex'));
  
  // 3. Decrypt the payload
  let decrypted = decipher.update(ciphertext, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  
  return JSON.parse(decrypted);
}
PHP
<?php
function decryptWebhookPayload($encryptedPayload, $webhookSecret) {
    $ciphertext = hex2bin($encryptedPayload['ciphertext']);
    $iv = hex2bin($encryptedPayload['iv']);
    $tag = hex2bin($encryptedPayload['tag']);
    
    // 1. Derive key via SHA-256 hash of secret
    $key = hash('sha256', $webhookSecret, true);
    
    // 2. Decrypt using openssl
    $decrypted = openssl_decrypt(
        $ciphertext,
        'aes-256-gcm',
        $key,
        OPENSSL_RAW_DATA,
        $iv,
        $tag
    );
    
    if ($decrypted === false) {
        throw new Exception('Decryption failed');
    }
    
    return json_decode($decrypted, true);
}
?>
Python (cryptography)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import hashlib
import json

def decrypt_webhook_payload(encrypted_payload, webhook_secret):
    ciphertext = bytes.fromhex(encrypted_payload['ciphertext'])
    iv = bytes.fromhex(encrypted_payload['iv'])
    tag = bytes.fromhex(encrypted_payload['tag'])
    
    # 1. Derive key via SHA-256 hash of secret
    key = hashlib.sha256(webhook_secret.encode('utf-8')).digest()
    
    # 2. Decrypt using AESGCM (cryptography expects ciphertext and tag concatenated)
    aesgcm = AESGCM(key)
    decrypted_bytes = aesgcm.decrypt(iv, ciphertext + tag, None)
    
    return json.loads(decrypted_bytes.decode('utf-8'))

6. คู่มือการเชื่อมต่อ API (API Integration Guide)

คำแนะนำทีละขั้นตอนสำหรับนักพัฒนาในการเชื่อมต่อระบบร้านค้า (Merchant System) เข้ากับเกตเวย์ P2P (Cross-Merchant P2P Gateway)

ขั้นตอนการฝากเงิน (Flow A: Deposit - Cash-In)

1
สร้างคำขอฝากเงิน (Create Order) ส่ง HTTP POST ไปที่ POST /api/v1/deposit โดยระบบจะตรวจสอบ Gas Balance ของร้านค้า จากนั้นทำการสำรอง (Reserve) Gas ในอัตรา 1:1 กับยอดฝาก เพื่อการันตีธุรกรรม และปรับสถานะเป็น PENDING_MATCH
2
รอจับคู่และรับพิกัดบัญชีปลายทาง (Order Matched) เมื่อระบบจับคู่กับผู้ถอนเงิน (Withdrawer) ได้สำเร็จ สถานะจะเปลี่ยนเป็น WAITING_PAYMENT และส่ง Webhook ไปยัง webhookUrl ของร้านค้า โดยจะมีรายละเอียดบัญชีธนาคารของผู้รับเงินปลายทางแนบไปด้วย
3
โอนเงินจริงและยืนยันการโอน (Transfer & Notify) ผู้ฝากเงินโอนเงินจริงผ่าน Mobile Banking ไปยังบัญชีธนาคารที่ได้รับ เมื่อโอนเรียบร้อย ระบบร้านค้าต้องส่งคำขอแจ้งว่าโอนสำเร็จแล้วไปที่ POST /api/v1/transaction/:id/transferred เพื่อปรับสถานะธุรกรรมเป็น PAID_UNCONFIRMED
4
คู่ค้าปล่อยเครดิตและเสร็จสิ้นธุรกรรม (Release & Settle) เมื่อฝั่งผู้ถอนเงินตรวจสอบยอดเงินเข้าบัญชีเรียบร้อยและกดยอมรับ รายการจะเปลี่ยนสถานะเป็น COMPLETED ค่า Gas ที่ล็อคไว้จะถูก Netting หักล้างและบันทึกดุลบัญชีอย่างเป็นทางการ

ขั้นตอนการถอนเงิน (Flow B: Withdraw - Cash-Out)

1
สร้างคำขอถอนเงิน (Create Withdraw) ส่ง HTTP POST ไปที่ POST /api/v1/withdraw โดยระบบจะนำคำขอนี้เข้าสู่ Matching Engine เพื่อรอการจับคู่กับรายการฝาก
2
รอรับการแจ้งเตือนการโอนเงิน (Wait Payment) เมื่อจับคู่สำเร็จและฝั่งผู้ฝากโอนเงินมาแล้ว สถานะจะปรับเปลี่ยนผ่าน Webhook เป็น PAID_UNCONFIRMED เพื่อส่งสัญญาณให้คุณไปตรวจสอบบัญชีธนาคารจริง
3
ตรวจสอบเงินเข้าและกดยืนยันปล่อยยอด (Verify & Release) หากเงินเข้าบัญชีธนาคารจริงอย่างถูกต้อง ให้ส่งคำขอไปที่ POST /api/transaction/:id/release เพื่อส่งเครดิตและจบธุรกรรม (สถานะ COMPLETED)
4
แจ้งเปิดข้อพิพาทเมื่อเกิดปัญหา (Dispute Override) หากเลยกำหนดเวลา (Timeout) หรือยอดเงินไม่เข้าจริง หรือผู้ฝากแนบสลิปปลอม ให้ส่งคำขอ POST /api/transaction/:id/dispute ทันที เพื่อระงับเวลาถอยหลัง และส่งธุรกรรมเข้าสู่ Dispute Center ให้แอดมินพิจารณาตัดสิน

ตัวอย่างการเขียนโปรแกรมเชื่อมต่อ (Code Examples)

Node.js (Axios) - Create Deposit Request
const axios = require('axios');

async function createDeposit() {
  try {
    const response = await axios.post('http://localhost:3005/api/v1/deposit', {
      merchantUserId: 'user_lucky_01',
      amount: '100.00',
      idempotencyKey: 'ik_' + Date.now()
    }, {
      headers: {
        'X-API-Key': 'key-lucky-games',
        'Content-Type': 'application/json'
      }
    });
    console.log('Order Created:', response.data);
  } catch (error) {
    console.error('API Error:', error.response ? error.response.data : error.message);
  }
}
PHP (cURL) - Create Deposit Request
<?php
$ch = curl_init('http://localhost:3005/api/v1/deposit');
$payload = json_encode([
    'merchantUserId' => 'user_lucky_01',
    'amount' => '100.00',
    'idempotencyKey' => 'ik_' . time()
]);

curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'X-API-Key: key-lucky-games'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);
curl_close($ch);
echo "Response: " . $result;
?>
Python (Requests) - Create Deposit Request
import requests
import time

url = "http://localhost:3005/api/v1/deposit"
headers = {
    "Content-Type": "application/json",
    "X-API-Key": "key-lucky-games"
}
payload = {
    "merchantUserId": "user_lucky_01",
    "amount": "100.00",
    "idempotencyKey": f"ik_{int(time.time())}"
}

response = requests.post(url, json=payload, headers=headers)
print("Response JSON:", response.json())

7. การหมุนเวียนคีย์โดยไม่หยุดชะงัก (Zero-Downtime API Key Rotation)

ในการหมุนเวียนคีย์ API (API Key Rotation) เกตเวย์จะเปิดใช้งานคีย์เดิมเป็น Transition Key อัตโนมัติเป็นเวลา 24 ชั่วโมงหลังจากสร้างคีย์ใหม่ ระบบหลังบ้านของร้านค้าสามารถส่งคำขอด้วยคีย์ใหม่ หรือใช้คีย์เดิมในช่วงเปลี่ยนผ่านได้โดยไม่มีช่วงระบบล่ม (Zero Downtime)

Node.js - Client SDK/Middleware Example (Automatic Key Rotation Fallback)
const axios = require('axios');

// เก็บคีย์ API ล่าสุด และคีย์สำรอง (Transition Key)
const apiClient = axios.create({
  baseURL: 'http://localhost:3005',
  timeout: 5000,
  headers: { 'Content-Type': 'application/json' }
});

const API_KEYS = {
  primary: 'key-rotated-8bf292cb', // คีย์ใหม่ล่าสุด
  transition: 'key-lucky-games'    // คีย์เก่า (ที่กำลังใช้งานในช่วงเปลี่ยนผ่าน)
};

// Middleware หรือ helper สำหรับยิง HTTP request แบบมี Failover
async function requestWithKeyRotation(endpoint, data) {
  // 1. ลองยิงด้วยคีย์ Primary ก่อน
  try {
    const response = await apiClient.post(endpoint, data, {
      headers: { 'X-API-Key': API_KEYS.primary }
    });
    console.log('Success with Primary Key!');
    return response.data;
  } catch (error) {
    // 2. หากเฟลด้วยสิทธิ์ไม่ถูกต้อง (401 Unauthorized) ให้ลอง fallback ยิงด้วย Transition Key
    if (error.response && error.response.status === 401 && API_KEYS.transition) {
      console.warn('Primary Key unauthorized. Trying Transition API Key...');
      try {
        const response = await apiClient.post(endpoint, data, {
          headers: { 'X-API-Key': API_KEYS.transition }
        });
        console.log('Success with Transition Key!');
        return response.data;
      } catch (fallbackError) {
        throw fallbackError;
      }
    }
    throw error;
  }
}

// วิธีเรียกใช้งาน
// requestWithKeyRotation('/api/deposit', { ... });

8. การตรวจสอบลายเซ็น Webhook (Webhook Signature Verification)

ในการส่งข้อมูลการอัปเดตสถานะธุรกรรม (Webhook) เกตเวย์จะคำนวณค่าแฮช HMAC-SHA256 ของ Payload ดิบด้วย Webhook Secret ของร้านค้า และส่งมาใน Header X-Webhook-Signature ร้านค้าต้องนำข้อมูลใน Body ทั้งหมดมาทำแฮชเปรียบเทียบในฝั่งเซิร์ฟเวอร์ปลายทางเพื่อยืนยันว่าข้อมูลส่งมาจากเกตเวย์จริงและไม่ได้ถูกปลอมแปลง (Signature Verification)

Node.js (Express) - Webhook Signature Verification Example
const express = require('express');
const crypto = require('crypto');
const app = express();

// หมายเหตุ: ต้องใช้ Raw Body เพื่อคำนวณลายเซ็นที่ถูกต้อง
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const webhookSecret = "your_whsec_secret_here"; // จะแทนที่ด้วยความลับจริงเมื่อเข้าระบบ

  const computedSignature = crypto
    .createHmac('sha256', webhookSecret)
    .update(req.body) // req.body ต้องเป็น Raw Buffer ที่ได้จาก express.raw
    .digest('hex');

  if (signature === computedSignature) {
    console.log('Webhook signature valid!');
    const payload = JSON.parse(req.body.toString());
    console.log('Processed Event:', payload.event, 'Transaction ID:', payload.data.id);
    res.sendStatus(200);
  } else {
    console.error('Webhook signature verification failed!');
    res.sendStatus(400);
  }
});

Register Partner (ลงทะเบียนพันธมิตร)

Partners Directory & Hierarchy

All registered Merchants and hierarchical Agents in the gateway database.

Registered Merchants

ID Name API Key (Password) Webhook URL Agent Dep Comm (%) Wit Comm (%) Action

Agents Hierarchy

ID Username Parent Agent Dep Comm Rate (%) Wit Comm Rate (%) Action

Create Staff Account (สร้างบัญชีผู้ดูแลระบบ)

Admins & Staff Directory

Staff User Role Permissions Status Actions

Pending Agent Top-Up Requests (รายการอนุมัติเติมเงินเอเยนต์)

Approve or reject top-up requests submitted by hierarchical agents after verifying their transfer slips.
Request ID Agent Requested Amount Slip Reference Submitted Time Actions

Pending Agent Cash-out Requests (รายการอนุมัติถอนเงินเอเยนต์)

Approve or reject withdrawal requests submitted by agents after manually transferring funds to their bank accounts.
Request ID Agent Requested Amount Bank Details Submitted Time Actions

Audit Operations

Execute database-to-ledger chain scans. Detect discrepancies and auto-resolve rounding imbalances.
Audit Status: UNCHECKED
Discrepancies: 0
Last Checked: Never

Integrity Audit Output Logs

Console ready. Click "Run Ledger Audit" to fetch logs.

Merchants Balance Integrity

Merchant Gas (DB/Ledger) Gas Status Credit (DB/Ledger) Credit Status
No audit data. Run audit to populate.

Agents Balance Integrity

Agent Wallet (DB/Ledger) Integrity Status
No audit data. Run audit to populate.

Audit Runs History (ประวัติการตรวจสอบสมดุลบัญชีแยกประเภท)

Historical record of ledger integrity runs executed by administrators or hourly automated cron tasks.
Checked Time Status Discrepancies Discrepancy Details
No audit run history found.

Recruit Sub-Agent (รับสมัครเอเยนต์ย่อย)

Create a new sub-agent under your account. The sub-agent's commission rates must be greater than or equal to your own rates.
Your Rates (เรตปัจจุบันของคุณ)
Deposit: 0.0% | Withdraw: 0.0%

Recruited Sub-Agents (รายชื่อสายเอเยนต์ย่อย)

List of all agents recruited directly or indirectly under your network node.
ID Username Parent Agent Dep Comm Rate (%) Wit Comm Rate (%) Wallet Balance (PTS)

Register Merchant (ลงทะเบียนร้านค้าย่อย)

Create a new merchant under your affiliate node. The merchant's commission rates cannot be lower than your own rates.

My Merchants (รายชื่อร้านค้าในเครือ)

List of all merchants associated with your agent account.
ID Name API Key (Password) Webhook URL Dep Comm (%) Wit Comm (%) Gas Balance (PTS) Action

Transfer Wallet (โอนคอมมิชชั่นให้สายล่าง)

Transfer your wallet balance down to one of your direct sub-agents.

Refill History (ประวัติการเติม Gas)

History of manual and automatic gas refills performed by your agent account.
Date Merchant Type Amount (PTS)

Merchant Profile & API Settings

Manage your Webhook URL. Secrets are only returned once when created or rotated.

โปรดตั้งค่า Whitelist ไอพีเหล่านี้ใน Firewall ของร้านค้า เพื่อรับเฉพาะ Webhook ที่แท้จริงจากระบบเรา:

54.86.50.139, 34.207.12.83, 127.0.0.1
The secret is never returned by profile or login APIs. Rotate it to receive a new value once.

Checkout Branding Settings (การตั้งค่าหน้ารับเงินของร้านค้า)

#3b82f6

Notification Settings (การตั้งค่าการแจ้งเตือน)

Webhook Connection Response

[System] Click "Test Webhook" to trigger a synchronous POST request and inspect the response logs.

Webhook Delivery Logs

Audit logs of webhook attempts for your merchant account. You can manually resend failed webhooks.
Log ID Tx ID Event URL HTTP Status Duration (ms) Response Body Timestamp Action
No webhook logs found.

Pending Webhook Deliveries (คิวรอส่งสัญญาณซ้ำ)

Webhooks that failed recently and are scheduled for exponential backoff retries. You can force an immediate retry or discard them.
Job ID Tx ID Tx Type Amount State Attempts Scheduled Next Retry Failed Reason Actions
No pending webhooks in retry queue.