Skip to content

公开 API 文档 ​

版本: 1.1.0 最后更新: 2025-12-24

环境 ​

环境Base URL描述
生产https://gateway.facaiqq.com/v1真实交易,实时支付
沙盒https://gateway.facaiqq.com/v1测试交易(仅限沙盒商户类型)

概述 ​

公开 API 使商户能够将支付处理功能集成到其应用程序中。所有 API 请求都需要 HMAC-SHA256 身份验证。

生产环境与沙盒环境 ​

商户类型决定交易路由:

  • 生产商户:通过支付提供商处理真实资金交易。
  • 沙盒商户:用于测试的模拟交易。响应在本地模拟,不进行外部处理。

身份验证 ​

所有 API 请求必须包含以下请求头:

请求头必填描述
X-API-Key是您的商户 API 密钥(64 个字符)
X-Signature是请求的 HMAC-SHA256 签名
X-Timestamp是Unix 时间戳(自 epoch 以来的秒数)
Content-Type是application/json

签名生成 ​

签名使用您的密钥通过 HMAC-SHA256 计算:

Signature = HMAC-SHA256(SignatureData, SecretKey)
SignatureData = METHOD|PATH|TIMESTAMP|BODY

示例(POST 请求):

SignatureData = "POST|/v1/payments/deposit|1702400000|{\"amount\":100.00,\"currency\":\"THB\",\"reference_id\":\"ORDER-001\"}"

示例(GET 请求):

SignatureData = "GET|/v1/payments/pay_abc123|1702400000"

代码示例 ​

python
import hmac
import hashlib
import time
import json
import requests

api_key = "your_api_key"
secret_key = "your_secret_key"
base_url = "https://gateway.facaiqq.com"

def create_signature(method, path, timestamp, body=""):
    # 重要:path 必须是完整的 HTTP 路径(例如 /v1/payments/deposit)
    data = f"{method}|{path}|{timestamp}"
    if body:
        data += f"|{body}"
    return hmac.new(
        secret_key.encode(),
        data.encode(),
        hashlib.sha256
    ).hexdigest()

def make_request(method, path, body=None):
    timestamp = str(int(time.time()))
    body_str = json.dumps(body) if body else ""
    signature = create_signature(method, path, timestamp, body_str)

    headers = {
        "X-API-Key": api_key,
        "X-Signature": signature,
        "X-Timestamp": timestamp,
        "Content-Type": "application/json"
    }

    url = base_url + path
    if method == "POST":
        return requests.post(url, headers=headers, json=body)
    else:
        return requests.get(url, headers=headers)

# 创建存款 - 注意:使用包含 /v1 的完整路径
response = make_request("POST", "/v1/payments/deposit", {
    "amount": 1000.00,
    "currency": "THB",
    "reference_id": "ORD888888888",
    "bank_code": "004",
    "bank_account_no": "1234567890",
    "bank_account_name": "test test",
    "webhook_url": "https://example.com/path/to/your/webhook"
})
print(response.json())
javascript
const crypto = require("crypto");
const axios = require("axios");

const apiKey = "your_api_key";
const secretKey = "your_secret_key";
const baseUrl = "https://gateway.facaiqq.com";

function createSignature(method, path, timestamp, body = "") {
  // 重要:path 必须是完整的 HTTP 路径(例如 /v1/payments/deposit)
  let data = `${method}|${path}|${timestamp}`;
  if (body) {
    data += `|${body}`;
  }
  return crypto.createHmac("sha256", secretKey).update(data).digest("hex");
}

async function makeRequest(method, path, body = null) {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const bodyStr = body ? JSON.stringify(body) : "";
  const signature = createSignature(method, path, timestamp, bodyStr);

  const headers = {
    "X-API-Key": apiKey,
    "X-Signature": signature,
    "X-Timestamp": timestamp,
    "Content-Type": "application/json",
  };

  const url = baseUrl + path;
  if (method === "POST") {
    return axios.post(url, body, { headers });
  } else {
    return axios.get(url, { headers });
  }
}

// 创建存款 - 注意:使用包含 /v1 的完整路径
makeRequest("POST", "/v1/payments/deposit", {
  amount: 1000.0,
  currency: "THB",
  reference_id: "ORD888888888",
  bank_code: "004",
  bank_account_no: "1234567890",
  bank_account_name: "test test",
  webhook_url: "https://example.com/path/to/your/webhook",
}).then((res) => console.log(res.data));
php
<?php
$apiKey = 'your_api_key';
$secretKey = 'your_secret_key';
$baseUrl = 'https://gateway.facaiqq.com';

function createSignature($method, $path, $timestamp, $body = '') {
    global $secretKey;
    // 重要:path 必须是完整的 HTTP 路径(例如 /v1/payments/deposit)
    $data = "$method|$path|$timestamp";
    if ($body) {
        $data .= "|$body";
    }
    return hash_hmac('sha256', $data, $secretKey);
}

function makeRequest($method, $path, $body = null) {
    global $apiKey, $baseUrl;

    $timestamp = time();
    $bodyStr = $body ? json_encode($body) : '';
    $signature = createSignature($method, $path, $timestamp, $bodyStr);

    $headers = [
        'X-API-Key: ' . $apiKey,
        'X-Signature: ' . $signature,
        'X-Timestamp: ' . $timestamp,
        'Content-Type: application/json'
    ];

    $ch = curl_init($baseUrl . $path);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyStr);
    }

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

    return json_decode($response, true);
}

// 创建存款 - 注意:使用包含 /v1 的完整路径
$response = makeRequest('POST', '/v1/payments/deposit', [
    'amount' => 1000.00,
    'currency' => 'THB',
    'reference_id' => 'ORD888888888',
    'bank_code' => '004',
    'bank_account_no' => '1234567890',
    'bank_account_name' => 'test test',
    'webhook_url' => 'https://example.com/path/to/your/webhook'
]);
print_r($response);
go
package main

import (
    "bytes"
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "strconv"
    "time"
)

const (
    apiKey    = "your_api_key"
    secretKey = "your_secret_key"
    baseURL   = "https://gateway.facaiqq.com"
)

func createSignature(method, path, timestamp, body string) string {
    // 重要:path 必须是完整的 HTTP 路径(例如 /v1/payments/deposit)
    data := fmt.Sprintf("%s|%s|%s", method, path, timestamp)
    if body != "" {
        data += "|" + body
    }
    h := hmac.New(sha256.New, []byte(secretKey))
    h.Write([]byte(data))
    return hex.EncodeToString(h.Sum(nil))
}

func makeRequest(method, path string, body interface{}) (map[string]interface{}, error) {
    timestamp := strconv.FormatInt(time.Now().Unix(), 10)

    var bodyStr string
    var reqBody io.Reader
    if body != nil {
        bodyBytes, _ := json.Marshal(body)
        bodyStr = string(bodyBytes)
        reqBody = bytes.NewBuffer(bodyBytes)
    }

    signature := createSignature(method, path, timestamp, bodyStr)

    req, _ := http.NewRequest(method, baseURL+path, reqBody)
    req.Header.Set("X-API-Key", apiKey)
    req.Header.Set("X-Signature", signature)
    req.Header.Set("X-Timestamp", timestamp)
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    return result, nil
}

func main() {
    // 创建存款 - 注意:使用包含 /v1 的完整路径
    result, _ := makeRequest("POST", "/v1/payments/deposit", map[string]interface{}{
        "amount":            1000.00,
        "currency":          "THB",
        "reference_id":      "ORD888888888",
        "bank_code":         "004",
        "bank_account_no":   "1234567890",
        "bank_account_name": "test test",
        "webhook_url":       "https://example.com/path/to/your/webhook",
    })
    fmt.Printf("%+v\n", result)
}

接口端点 ​

创建存款 ​

创建新的存款支付请求。返回 PromptPay 二维码供客户支付。

POST /v1/payments/deposit

请求体 ​

字段类型必填描述
amountnumber是支付金额(> 0)
currencystring是货币代码(3 个字符,例如 "THB")
reference_idstring是您的唯一订单参考号(1-64 个字符)
customer_emailstring否客户邮箱,用于通知
customer_phonestring否客户电话号码(最多 20 个字符)
descriptionstring否支付描述(最多 255 个字符)
webhook_urlstring否支付通知的 Webhook URL
bank_codestring否付款人银行代码(3 位数字),用于参考
bank_account_nostring否付款人银行账号(最多 20 个字符)
bank_account_namestring否付款人银行账户持有人姓名(最多 100 个字符)

请求示例 ​

json
{
  "amount": 1000.00,
  "currency": "THB",
  "reference_id": "ORD888888888",
  "bank_code": "004",
  "bank_account_no": "1234567890",
  "bank_account_name": "test test",
  "webhook_url": "https://example.com/path/to/your/webhook"
}

响应 ​

响应格式取决于 amount 金额是否达到管理员设定的阈值(以下示例使用 5000 仅供说明 — 实际阈值由管理员配置)。

当 amount 低于阈值(例如 < 5000)时 — 通过 PromptPay 二维码支付

company_account = false,并照常返回 PromptPay 二维码。

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888888",
  "type": "deposit",
  "status": "pending",
  "amount": 1000.00,
  "currency": "THB",
  "company_account": false,
  "qr_code": "00020101021129370016A000000677010111011300668123456785802TH5303764...",
  "qr_code_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
  "created_at": "2025-12-24T10:30:00Z",
  "expires_at": "2025-12-24T10:45:00Z"
}

当 amount 达到阈值(例如 >= 5000)时 — 转账至公司账户

company_account = true,并附带公司账户信息(company_account_bank_code、company_account_bank_name、company_account_name、company_account_no)。此响应中不会返回 qr_code / qr_code_image 字段。

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888888",
  "type": "deposit",
  "status": "pending",
  "amount": 5000.00,
  "currency": "THB",
  "company_account": true,
  "company_account_bank_code": "004",
  "company_account_bank_name": "开泰银行",
  "company_account_name": "示例公司有限公司",
  "company_account_no": "1234567890",
  "created_at": "2025-12-24T10:30:00Z",
  "expires_at": "2025-12-24T10:45:00Z"
}

响应字段 ​

字段类型描述
idstring唯一交易 ID(UUID 格式)
reference_idstring您的订单参考号
typestring交易类型(deposit)
statusstring支付状态
amountnumber支付金额
currencystring货币代码
company_accountboolean公司账户标志 — 当 amount 达到管理员设定的阈值时为 true(转账至公司账户),低于阈值时为 false(通过二维码支付)。5000 仅为示例阈值。
company_account_bank_codestring公司账户银行代码(3 位数字)(仅当 company_account = true 时返回)
company_account_bank_namestring公司账户银行名称(仅当 company_account = true 时返回)
company_account_namestring公司账户持有人姓名(仅当 company_account = true 时返回)
company_account_nostring公司账号(仅当 company_account = true 时返回)
qr_codestringPromptPay 二维码字符串(仅当 company_account = false 时返回)
qr_code_imagestringBase64 编码的二维码图片,PNG(仅当 company_account = false 时返回)
created_atstring创建时间戳(ISO 8601)
expires_atstring过期时间戳(ISO 8601,默认 15 分钟)

创建提款 ​

创建新的提款/付款请求到银行账户。

POST /v1/payments/withdraw

请求体 ​

字段类型必填描述
amountnumber是提款金额(> 0)
currencystring是货币代码(3 个字符)
reference_idstring是您的唯一参考号(1-64 个字符)
bank_codestring是银行代码(3 位数字,见下表)
account_numberstring是银行账号(10-20 位数字)
account_holder_namestring是账户持有人姓名(1-100 个字符)
descriptionstring否转账描述(最多 255 个字符)
webhook_urlstring否转账通知的 Webhook URL

银行代码 ​

代码泰文名称英文名称
002ธนาคารกรุงเทพBangkok Bank PCL (BBL)
004ธนาคารกสิกรไทยKasikornbank PCL (Kbank)
006ธนาคารกรุงไทยKrungthai Bank PCL (KTB)
011ธนาคารทหารไทยธนชาตTMBThanachart Bank PCL (TTB)
014ธนาคารไทยพาณิชย์Siam Commercial Bank PCL (SCB)
017ธนาคารซิตี้แบงก์Citibank N.A.
020ธนาคารสแตนดาร์ดชาร์เตอร์ด (ไทย)Standard Chartered Bank (Thai) PCL
022ธนาคารซีไอเอ็มบี ไทยCIMB Thai Bank PCL
024ธนาคารยูโอบีUnited Overseas Bank (Thai) PCL
025ธนาคารกรุงศรีอยุธยาBank of Ayudhya PCL (Krungsri)
026ธนาคารเมกะสากลพาณิชย์Mega International Commercial Bank
030ธนาคารออมสินGovernment Savings Bank (GSB)
031ธนาคารฮ่องกงและเซี่ยงไฮ้HSBC Thailand
033ธนาคารอาคารสงเคราะห์Government Housing Bank (GHB)
034ธนาคารเพื่อการเกษตรฯBAAC
065ธนาคารธนชาตThanachart Bank PCL
066ธนาคารอิสลามแห่งประเทศไทยIslamic Bank of Thailand
067ธนาคารทิสโก้TISCO Bank PCL
069ธนาคารเกียรตินาคินภัทรKiatnakin Phatra Bank PCL (KKP)
070ธนาคารไอซีบีซี (ไทย)ICBC (Thai) PCL
071ธนาคารไทยเครดิตThai Credit Retail Bank
073ธนาคารแลนด์ แอนด์ เฮ้าส์Land and Houses Bank PCL (LH Bank)
088ธนาคารคลิกซ์Clicx Bank
PROMPTPAYพร้อมเพย์PromptPay
TRUEทรูมันนี่TrueMoney

PromptPay 提款 ​

当使用 bank_code: "PROMPTPAY" 时,account_number 字段应包含:

账号长度代理类型描述
10 位数字MOBILE手机号码
13 位数字TXID身份证号或税务 ID

请求示例(使用手机号的 PromptPay):

json
{
  "amount": 5000.00,
  "currency": "THB",
  "reference_id": "ORD888888890",
  "bank_code": "PROMPTPAY",
  "account_number": "0812345678",
  "account_holder_name": "John Doe"
}

请求示例(使用身份证号的 PromptPay):

json
{
  "amount": 5000.00,
  "currency": "THB",
  "reference_id": "ORD888888891",
  "bank_code": "PROMPTPAY",
  "account_number": "1234567890123",
  "account_holder_name": "John Doe"
}

请求示例 ​

json
{
  "amount": 5000.00,
  "currency": "THB",
  "reference_id": "ORD888888889",
  "bank_code": "014",
  "account_number": "1234567890",
  "account_holder_name": "John Doe",
  "webhook_url": "https://example.com/path/to/your/webhook"
}

响应 ​

json
{
  "id": "660e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORD888888889",
  "type": "withdraw",
  "status": "processing",
  "amount": 5000.00,
  "currency": "THB",
  "created_at": "2025-12-24T11:00:00Z"
}

获取支付详情 ​

通过支付 ID 检索支付详情。

GET /v1/payments/{id}

路径参数 ​

参数类型描述
idstring支付 ID(UUID 格式)

响应示例 ​

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORDER-2024-001",
  "type": "deposit",
  "status": "completed",
  "amount": 1500.00,
  "currency": "THB",
  "qr_code": "00020101021129370016A000000677010111...",
  "created_at": "2024-12-12T10:30:00Z",
  "expires_at": "2024-12-12T10:45:00Z"
}

取消支付 ​

取消待处理的支付。只有状态为 pending 的支付才能被取消。

POST /v1/payments/{id}/cancel

路径参数 ​

参数类型描述
idstring要取消的支付 ID

响应示例 ​

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "reference_id": "ORDER-2024-001",
  "type": "deposit",
  "status": "cancelled",
  "amount": 1500.00,
  "currency": "THB",
  "created_at": "2024-12-12T10:30:00Z"
}

支付状态 ​

状态描述
pending支付已创建,等待客户操作
processing支付正在处理中
completed支付成功完成
failed支付失败(包括过期的交易)
cancelled支付已取消
refunded支付已退款

提示

当支付过期(客户未在时间限制内支付)时,状态会变为 failed,失败原因为 "Transaction expired"。系统会发送 Webhook 通知您的系统。


Webhooks ​

当您提供 webhook_url 时,我们将发送 POST 请求以更新支付状态。

Webhook 负载 ​

Webhook 负载直接发送(不包装在事件结构中):

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "deposit",
  "amount": 1500.00,
  "fee": 37.50,
  "netAmount": 1462.50,
  "bankAccountNo": "1234567890",
  "bankAccountName": "SOMCHAI JAIDEE",
  "bankCode": "014",
  "bankName": "ธนาคารไทยพาณิชย์",
  "currency": "THB",
  "referenceNo": "ORDER-2024-001",
  "status": "success",
  "timestamp": "2024-12-12T10:35:00Z",
  "paidAt": "2024-12-12T10:34:55.123456789Z"
}

Webhook 负载字段 ​

字段类型描述
idstring交易 ID
typestring交易类型:deposit 或 withdraw
amountnumber原始支付金额
feenumber收取的处理费
netAmountnumber扣除费用后的金额
bankAccountNostring银行账号(用于有付款人信息的存款)
bankAccountNamestring银行账户持有人姓名
bankCodestring银行代码
bankNamestring银行名称(泰文)
currencystring货币代码
referenceNostring您的参考 ID
statusstringsuccess、failed 或 expired
timestampstringWebhook 发送时间戳(ISO 8601)
paidAtstring支付完成时间(如未支付则为空)

Webhook 状态值 ​

状态描述
success支付成功完成
failed支付失败或过期
expired支付过期(旧版,现在使用 failed)

Webhook 重试策略 ​

  • 如果发送失败,Webhook 最多重试 5 次
  • 重试间隔:每次尝试之间 1 分钟
  • 成功发送是任何 2xx HTTP 响应
  • 5 次失败尝试后,Webhook 将被标记为失败

Webhook 验证 ​

Webhook 请求包含用于验证的请求头:

请求头描述
X-Webhook-Signature请求体的 HMAC-SHA256 签名
X-Webhook-TimestampWebhook 的 Unix 时间戳
Content-Typeapplication/json

使用与 API 请求相同的 HMAC 方法验证 Webhook:

python
import hmac
import hashlib

def verify_webhook(body, signature, timestamp, secret_key):
    expected = hmac.new(
        secret_key.encode(),
        f"{timestamp}|{body}".encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

错误响应 ​

所有错误遵循以下格式:

json
{
  "code": "ERROR_CODE",
  "message": "Human-readable error message"
}

HTTP 状态码 ​

状态码描述
200成功
201创建成功
400请求错误 - 无效参数
401未授权 - 无效的 API 密钥或签名
403禁止 - 商户未激活或权限不足
404未找到
409冲突 - 重复的 reference_id
500内部服务器错误
504网关超时

错误代码 ​

代码描述
INVALID_REQUEST请求体验证失败
MISSING_API_KEY缺少 X-API-Key 请求头
MISSING_SIGNATURE缺少 X-Signature 请求头
MISSING_TIMESTAMP缺少 X-Timestamp 请求头
INVALID_API_KEYAPI 密钥无效
INVALID_SIGNATURE签名验证失败
INVALID_TIMESTAMP时间戳格式无效
TIMESTAMP_EXPIRED请求时间戳超出有效窗口
MERCHANT_INACTIVE商户账户未激活
PAYMENT_NOT_FOUND未找到支付
PAYMENT_ERROR一般支付处理错误
DUPLICATE_REFERENCE参考 ID 已存在
INSUFFICIENT_BALANCE提款余额不足
INVALID_BANK_CODE无效的银行代码
INVALID_ACCOUNT无效的银行账户(沙盒)
PAYMENT_CANNOT_BE_CANCELLED支付无法取消
TIMEOUT请求超时

沙盒测试 ​

沙盒工作原理 ​

沙盒模式由您的商户类型决定,而不是单独的 URL。沙盒和生产商户使用相同的 API 端点:

Base URL: https://gateway.facaiqq.com/v1

  • 沙盒商户:交易存储在沙盒数据库中。不处理真实资金。
  • 生产商户:交易存储在生产数据库中,并通过支付提供商处理。

请联系支持团队申请用于测试的沙盒凭证。

测试金额 ​

在沙盒模式下,特定金额会触发不同的行为:

金额货币行为描述
100.00THBauto_approve支付立即完成
200.00THBauto_pending支付保持待处理(模拟延迟)
500.00THBauto_approve支付立即完成
888.88THBtimeout支付超时
999.99THBauto_fail支付立即失败
1000.00THBauto_approve支付立即完成
其他THBpending正常支付流程

测试场景 ​

您可以使用 X-Sandbox-Scenario 请求头覆盖行为:

场景描述
auto_approve强制支付立即完成
auto_fail强制支付失败
auto_pending强制支付保持待处理
timeout模拟超时
invalid_account模拟无效银行账户(仅限提款)

示例:

bash
curl -X POST https://gateway.facaiqq.com/v1/payments/deposit \
  -H "X-Sandbox-Scenario: auto_approve" \
  -H "X-API-Key: your_sandbox_api_key" \
  -H "X-Signature: ..." \
  -H "X-Timestamp: ..." \
  -H "Content-Type: application/json" \
  -d '{"amount": 500.00, "currency": "THB", "reference_id": "TEST-001"}'

响应头 ​

响应包含指示环境的请求头:

请求头值描述
X-Environmentsandbox 或 production指示商户类型

交易过期 ​

  • 存款交易默认过期时间为 15 分钟
  • 如果客户在此时间内未支付:
    • 状态变为 failed(不是 expired)
    • failure_reason 设置为 "Transaction expired"
    • 发送 Webhook,status: "failed"
  • 过期检查每 1 分钟运行一次

速率限制 ​

端点速率限制
所有端点100 次请求/分钟
创建存款30 次请求/分钟
创建提款20 次请求/分钟

响应中包含速率限制请求头:

请求头描述
X-RateLimit-Limit每个窗口的最大请求数
X-RateLimit-Remaining窗口内剩余的请求数
X-RateLimit-Reset限制重置的 Unix 时间戳

支持 ​

如需技术支持:

FacaiQQ 支付网关