API 接入指南
面向商户和开发者的银行转账凭证自动验证 API 接入指南
Base URL
本文档中所有 endpoint 的基础地址
https://api.slip2try.comAPI 版本 v1(所有 endpoint 均位于 /api/v1 下)· 最近更新 2026-10-23
- 每分钟发送错误密钥超过 30 次的 IP:无效密钥现在返回 HTTP 429 和新的 reason auth_locked(原为 rate_limited——在收到 rate_limited 时退避的代码也请处理 auth_locked)· 同一 IP 正在使用的有效密钥可正常使用
- 每分钟限额现在按正式密钥(live)和测试密钥(test)分别计算——测试再多也不会占用正式密钥的额度 · 所有通过密钥校验的响应都带有 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset(秒)header
- /usage:today.calls 只统计银行已判定的凭证(不含验证前被拒绝的请求和系统故障)· 新增 environment 和 breakdown { denied, errors } · 测试密钥统计其模拟验证
- Webhook:轮换 Secret 后 24 小时内还会发送 X-VerifySlips-Signature-Previous header(用旧 Secret 的 V1 签名),仍校验 V1 的系统不会中断 · 在触发该推送的 API 响应返回后立即发送第一次推送(不会早于 API 响应)
- Webhook:可在 Webhook 页面轮换 Secret——旧 Secret 会在新的 X-VerifySlips-Signature-V2-Previous header 中继续签名 24 小时,可无缝更新您的 Secret
- Webhook:可暂停发送——暂停期间不会将新事件加入队列(恢复后不补发)· 测试按钮和已在等待重试的记录仍会发送
- 后台:API 调用记录(所有密钥验证通过的请求,保留 14 天,可按 requestId 搜索)· 使用测试密钥的 API 调试页面 · 含接入清单的开发者概览
- /api/v1/* 的所有非 2xx 响应现采用统一格式:success: false、status、code、reason、message 和 requestId(400 参数错误另含 param 指明字段)· 不存在的 path 以相同格式返回 404 not_found · 401 在下一个版本前仍保留旧字段 error: invalid api key
- POST /api/v1/verify/slip 现支持 multipart/form-data:图片放在 file 字段(或改为发送 qrData),expectedAmount 可选
- 新增 reason:invalid_api_key(401)、payload_too_large(413)、unsupported_media_type(415)、too_many_failed(429)和 internal_error(500)
- 所有 429 和 503 响应都带有 Retry-After header(秒),测试密钥也一样:rate_limited = 60 · temporarily_unavailable = 5 · too_many_failed 和测试密钥每日上限 = 距离重置的秒数
- Webhook:body 顶层新增 id(重试时保持不变——用于去重)和 environment · 新增 header X-VerifySlips-Delivery · verify.* 包含 channel 和 requestId
- /balance、/usage 和 /ping 返回 requestId · /balance 返回 environment · /usage 统计所有渠道(API + LINE + 网页)的验证
- Authorization 中的 Bearer 不区分大小写 · 先校验 expectedAmount 再读取图片 · WebP 图片返回 415 · 回调 URL 必须为 https · 查询类 endpoint 在上游数据源故障时返回 503 temporarily_unavailable
- 转账详情的标准路径为 data.transfer——data.slipVerification.transfer 仍会返回,但已弃用(deprecated)
创建 API 密钥 → 发送凭证验证请求 → 查看历史记录
- 第 1 步
创建 API 密钥
注册后前往 API 密钥页面创建密钥(系统不会自动创建)。密钥只显示一次——请复制并保存在服务器端。
- 第 2 步
发送凭证二维码进行验证
读取凭证上的二维码内容(以 00... 开头),发送至
POST /api/v1/verify/slip响应中的data.transfer包含实际金额,duplicate表示是否为重复凭证 - 第 3 步
每一笔结果均可追溯
所有请求都会被记录。点击某一行即可查看凭证详情、付款人、收款人、金额和来源 IP。
正式收款前必须做好的 8 件事
- 1只从您的服务器调用 API——切勿把密钥放进网页或 App · 开发时使用 s2t_test_ 密钥,上线时换成 s2t_live_
- 2每次验证凭证都发送 expectedAmount = 订单金额
- 3仅当 success && !duplicate && warnings.length === 0 && environment === "live" 时才发货——其他情况一律拒绝或转人工审核
- 4从 data.transfer 读取转账详情 · 将 transactionRef 设为唯一键,并把 verificationId 与订单一起保存
- 5只根据 success + reason 区分情况——切勿依据 message 文本
- 6客户端超时设为 60 秒 · 超时或连接中断时,先用 GET /api/v1/verifications?qrData=(或 ?requestId=)查询结果,再决定是否重发
- 7收到 429 或 503 时按 Retry-After 等待后再重试 · 大量请求请排队发送(默认每个店铺每分钟 120 次)
- 8Webhook:基于 Raw Body 校验 X-VerifySlips-Signature-V2,并拒绝时间偏差超过 5 分钟的请求 · 用 body 中的 id 去重 · 10 秒内返回 2xx
左侧为请求代码,右侧为解析后的凭证字段及已核验的银行标志。
请求代码
POST /api/v1/verify/slip
# 仅当 success: true、duplicate: false、warnings: [] 且 environment: "live" 时才发货 · expectedAmount = 订单金额
curl -X POST https://api.slip2try.com/api/v1/verify/slip \
--max-time 60 \
-H "Authorization: Bearer s2t_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"qrData":"0038000600000101030060217A3828f7b4f3244ff35102TH910480CE","expectedAmount":100000}'
# 超时或连接中断:先查询结果再决定是否重发(不扣配额)
curl -G https://api.slip2try.com/api/v1/verifications \
--max-time 60 \
-H "Authorization: Bearer s2t_live_xxxxxxxx" \
--data-urlencode "qrData=0038000600000101030060217A3828f7b4f3244ff35102TH910480CE"密钥只能保存在服务器端
s2t_live_xxxxxxxx 替换为您的真实密钥,切勿将密钥写入网页前端或移动应用代码——只能从您的后端服务器(Backend Server)调用。凭证解析示例

Krungthai Business · Krungthai Bank
已与银行核验一致
ktb转账金额
100,000.00 泰铢

付款账户
น.ส.สมศรี ใจดี

收款账户
EXAMPLE CO., LTD.
- transactionRef
- A3828f7b4f3244ff3
- transactionDateTime
- 2026-09-01T17:51:01+07:00
- amount.amount
- 100,000.00 泰铢
- duplicate
- false · 新凭证
所有服务商结构一致
data.transfer 的代码,即可直接用于 KTB、CIMB、SCB 和 Slip2Go。每次充值或发货前都要检查 duplicate
success: true 并不代表是一笔新付款
success 只表示银行确认凭证真实。如果 duplicate: true,说明您的店铺已成功验证过这张凭证,客户可能在重复使用旧凭证。如何解读结果
| 响应 | 结果 | 处理方式 |
|---|---|---|
| success: true · duplicate: false | 新凭证 | 可以充值 / 发货 |
| success: true · duplicate: true | 重复凭证 | 拒绝——客户可能在使用旧凭证 |
| success: false | 验证未通过 | 不要发货,请客户核对凭证 |
首次验证将返回 duplicate: false 和 duplicateInfo: null
重复凭证的响应示例
{
"success": true,
"cached": true,
"duplicate": true,
"duplicateInfo": {
"firstVerifiedAt": "2026-10-14T04:14:49.145Z",
"previousCount": 2
},
"data": { "...": "转账详情与首次验证时相同" }
}仅按您的店铺计算
其他店铺验证过这张凭证,不会算作您店铺的重复——您店铺首次验证仍正常扣除 1 张
按二维码或参考号判断重复
相同二维码,或二维码不同但
transactionRef相同,都算重复,且重复凭证不扣额度未通过的验证不计入
验证未通过的请求不会被算作之前的验证
并发请求只有一个结果
同一张凭证同时发送多个请求时,只有一个请求会得到
duplicate: falseWebhook 同样会告知
verify.success包含data.duplicate和data.firstVerifiedAt在后台查看历史
验证记录 页面带有“重复凭证”标签和筛选功能
在您的系统中再加一层保护
transactionRef 设为唯一键(unique),以防您的代码重复调用或重复收到 webhook。正式上线前,用测试密钥试遍所有情况——模拟结果,不调用银行,不扣配额
- 测试密钥以
s2t_test_开头——在 API 密钥页面创建时选择“测试”类型即可,Base URL 和 endpoint 与正式密钥相同 - 立即返回模拟结果:不发送给银行或验证系统,不扣配额,店铺尚无套餐也可使用
- 每个店铺每天最多可用测试密钥验证 1,000 次(超出返回 HTTP 429 reason: rate_limited)· 测试结果保留 7 天
- Webhook 仍按所选事件推送,但带有
X-VerifySlips-Test: trueheader,body 中包含"environment": "test",且失败后不会重试 - 再次发送相同二维码 = duplicate: true,与正式环境一致 · 也可发送凭证图片(系统从图片读取二维码后按相同规则处理)· 收款二维码(000201…)仍返回 400 payment_qr
- 测试密钥只能看到测试结果,正式密钥只能看到正式结果(GET /api/v1/verifications)· ping 返回 environment: test 和 ready: true
测试结果并非真实到账
environment,测试结果绝不发货——正式上线时请改用 s2t_live_ 密钥通过二维码内容的结尾指定结果
| 二维码结尾 | 结果 | 响应中 |
|---|---|---|
| …FAIL | 银行未通过验证(HTTP 200,无 reason)——推送 verify.failed webhook | success: false |
| …ERROR | 验证系统暂时故障——可重试 | HTTP 503 · reason: temporarily_unavailable |
| …DUP | 重复凭证——duplicateInfo 提供首次验证时间 | duplicate: true · warnings: ["duplicate"] |
| …MISMATCH | 转入其他账户(checks.receiver: mismatch) | warnings: ["receiver_mismatch"] |
| …AMOUNT | 金额与 expectedAmount 不符(checks.amount: mismatch)——需同时发送 expectedAmount | warnings: ["amount_mismatch"] |
| …OLD | 转账时间为 48 小时前(checks.stale: true) | warnings: ["stale_slip"] |
| 其他 | 通过——金额 = expectedAmount(未发送时为 100 泰铢)· 收款方 = 店铺的第一个收款账户(未设置时为 not_configured) | success: true · warnings: [] |
系统查看 qrData 的结尾(不区分大小写),例如 ORDER-1001-FAIL——qrData 长度仍须为 10–1000 个字符,与正式环境相同
示例
Request · 测试密钥
curl -X POST https://api.slip2try.com/api/v1/verify/slip \
-H "Authorization: Bearer s2t_test_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"qrData":"TEST-ORDER-1001-AMOUNT","expectedAmount":250}'点击各项可展开或收起,查看需要发送的参数、Request 示例,以及成功和失败时的 Response 格式。
发送凭证图片或凭证上的二维码内容,系统将向银行核验并返回真实的转账详情,并检查是否为旧凭证以及是否转入店铺账户。
Scope: verify:slip
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
qrData | string | 从凭证二维码读取的内容,通常以 00 开头——请按读取结果发送整个字符串,不要转换大小写或删减字符(首尾空格由系统自动去除)· qrData 与 image 二选一 | |
image | string (base64) | 凭证图片(JPEG/PNG)的 base64,可带 data:image/…;base64, 前缀,系统会代为读取二维码——图片约 3 MB 以内(body 总计不超过 4 MB)· 也可直接以图片文件作为 body 发送(Content-Type: image/jpeg 或 image/png),或使用 multipart/form-data 的 file 字段——整个请求最大 4 MB · WebP、GIF、HEIC、AVIF 和 PDF 返回 415 unsupported_media_type | |
expectedAmount | number | string | 订单金额(泰铢),系统会与凭证金额比对——建议每次都发送 · 数字或数字字符串,大于 0,最多 2 位小数 · 直接以图片作为 body 发送时,请在 URL 中使用 ?expectedAmount=,multipart 则作为文本字段 expectedAmount 发送 · 在读取图片之前校验,无效值返回 400 invalid_request(param: expectedAmount) |
Request 示例
{
"qrData": "0038000600000101030060217A3828f7b4f3244ff35102TH910480CE",
"expectedAmount": 100000
}Response 示例
{
"status": "Success",
"code": "200",
"success": true,
"message": "Bank slip QR code verified successfully",
"qrData": "0038000600000101030060217A3828f7b4f3244ff35102TH910480CE",
"verificationId": "6f1c2a9e-4b7d-4c1e-9a52-0d3f8e7b1c24",
"environment": "live",
"source": "qr",
"requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c",
"provider": "ktb",
"cached": false,
"duplicate": false,
"duplicateInfo": null,
"warnings": [],
"checks": {
"stale": false,
"slipAgeHours": 0.1,
"receiver": "matched",
"receiverLabel": "บัญชีหลัก",
"amount": "matched",
"expectedAmount": 100000
},
"data": {
"type": "SLIP_VERIFICATION",
"payment": null,
"transfer": {
"transactionRef": "A3828f7b4f3244ff3",
"transactionDateTime": "2026-09-01T17:51:01+07:00",
"fromBankCode": "006",
"fromBankName": "กรุงไทย",
"fromAccountNo": "XXX-X-XX123-4",
"fromAccountName": "น.ส.สมศรี ใจดี",
"fromAccountNameTh": "น.ส.สมศรี ใจดี",
"fromAccountNameEn": "MS SOMSRI JAIDEE",
"toBankCode": "014",
"toBankName": "ไทยพาณิชย์",
"toAccountNo": "XXX-X-XX567-8",
"toAccountName": "EXAMPLE CO., LTD.",
"toAccountNameTh": "บริษัท ตัวอย่าง จำกัด",
"toAccountNameEn": "EXAMPLE CO., LTD.",
"amount": {
"amount": 100000,
"currency": { "code": "THB", "displayName": "บาท", "symbol": "฿" }
}
},
"slipVerification": {
"transfer": { "...": "已弃用,与 data.transfer 数据相同" }
}
}
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
success | boolean | 银行是否确认该凭证——请检查此值,而不是 HTTP status |
verificationId | string | 本次验证的 ID——与 webhook 中的 data.verificationId 相同,可用 GET /api/v1/verifications/:id 查询结果(请求因 reason 被拒绝时不包含) |
environment | "live" | "test" | live = 正式密钥,向银行核验 · test = 测试密钥,模拟结果(切勿据此决定发货) |
warnings | string[] | 发货前需要检查的项目:duplicate · receiver_mismatch · amount_mismatch · stale_slip——空数组表示无需担心 |
checks.receiver | string | matched = 转入店铺设置的收款账户 · mismatch = 转入其他账户 · not_configured = 店铺尚未设置收款账户(可在 LINE Bot 页面设置) |
checks.amount | string | matched = 金额与 expectedAmount 一致 · mismatch = 不一致(warnings 包含 amount_mismatch)· not_checked = 未发送 expectedAmount |
checks.expectedAmount | number | null | 您发送用于比对的金额(null = 未发送) |
checks.stale | boolean | true = 转账时间超过 24 小时或在未来——可能是旧的真实凭证被用于新订单 |
requestId | string | 请求 ID,与 X-Request-Id 响应头相同——联系客服时附上,我们可立即找到该请求 |
source | string | qr = 您发送了二维码内容 · image = 系统从图片中读取二维码 |
duplicate | boolean | true = 您的店铺已成功验证过这张凭证,每次充值或发货前都必须检查 |
duplicateInfo.firstVerifiedAt | string | null | 首次验证成功的时间(ISO 8601)——duplicate: false 时整个对象为 null |
duplicateInfo.previousCount | number | 您的店铺此前成功验证这张凭证的次数 |
cached | boolean | true = 结果来自系统共享缓存(该凭证此前已验证成功,无需再次询问银行)——仅当是您店铺的重复凭证(duplicate: true)时不扣额度;由其他店铺首次验证的凭证仍扣 1 张 |
provider | string | null | 响应此请求的验证方,例如 ktb(可能为 null) |
data.transfer | object | 所有转账详情——请从此 path 读取 |
…transfer.transactionRef | string | 交易参考号,用于防止凭证重复使用,也可在记录页面中搜索 |
…transfer.transactionDateTime | string | 银行返回的交易时间(ISO-8601 字符串)——格式和时区可能因银行而异 |
…transfer.amount.amount | number | null | 金额(泰铢)——嵌套在 amount 下一层,例如 100000 表示十万泰铢(不是萨当),可能为 null |
…transfer.fromAccountNo | string | 付款人账号,部分数字已由银行遮蔽 |
data.slipVerification.transfer | object | data.transfer 的旧名称(数据相同)——已弃用(deprecated),新代码请读取 data.transfer |
注意事项与建议
- 所有服务商的响应结构相同,一套代码即可适用——但字段的值以银行返回为准。
- transactionDateTime 按银行返回的原样传递(ISO-8601)——请用日期库解析,不要自行截取字符串,也不要假定固定时区。
- provider 和 amount.amount 可能为 null——如需根据金额做判断,请先确认有值。
- 当收款方为 PromptPay 或电子钱包时,toBankCode 可能为空——请勿假定它始终有值。
- 账号遮蔽由各银行自行处理,因此格式可能不同,例如 xxxx-xx328-0 与 xxxxxx3280——请改用 transactionRef 作为参考依据。
- 账户名称有 Th 和 En 两种,部分银行不会全部返回,请做好值为 null 的处理。
- cached: true 表示结果来自共享缓存(更快)。您店铺的重复凭证不额外扣额度并带有 duplicate: true;由其他店铺首次验证的凭证仍扣 1 张——参见“防止重复凭证”。
- 银行未通过验证时响应不包含 reason 字段——只有非 2xx 响应(被拒绝或出错,见“拒绝与错误”)才会返回 reason。success: false 且没有 reason 表示银行未能通过该凭证的验证,例如凭证过旧或找不到该交易。
- message 文本为泰文且可能调整——请仅根据 success、duplicate、warnings 和 reason 编写逻辑。
- success: true 表示银行确认凭证为真——仍需检查 warnings:receiver_mismatch = 款项未转入您的账户 · amount_mismatch = 金额与 expectedAmount 不符 · stale_slip = 旧凭证(系统不会自动拒绝,请按您的规则处理)
- 同时发送 expectedAmount,系统会代为比对金额——金额不符时仍为 success: true,但带有 warnings: amount_mismatch 和 checks.amount: mismatch(银行未返回金额时视为不符)
- 直接上传图片:curl -X POST "…/api/v1/verify/slip?expectedAmount=250" -H "Authorization: Bearer $API_KEY" -H "Content-Type: image/jpeg" --data-binary @slip.jpg(无需比对金额时可省略 ?expectedAmount=)
- 客户端超时请设为 60 秒。请求超时或连接中断时,请勿立即重发凭证——先调用 GET /api/v1/verifications?qrData=…(如已拿到 X-Request-Id header,也可用 ?requestId=…)查询结果,不扣配额。若重发后得到 duplicate: true,请确认首次验证是否就是您自己那次超时的请求
- multipart/form-data 上传:curl -X POST "…/api/v1/verify/slip" -H "Authorization: Bearer $API_KEY" -F "file=@slip.jpg" -F "expectedAmount=250"——file 字段放 JPEG/PNG(或用文本字段 qrData 代替图片)· 整个请求最大 4 MB · 响应中 source 为 image
- 测试密钥(s2t_test_…)返回带有 environment: test 的模拟结果——参见“测试模式”
- 收款二维码(PromptPay / 商户二维码,以 000201 开头)不是凭证二维码——会立即返回 reason: payment_qr,不扣额度
通过 verificationId(来自验证响应或 webhook)获取历史结果——不会重新验证,也不扣配额
Scope: verify:slip
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string (path) | 必填 | 来自 POST /api/v1/verify/slip 响应的 verificationId,或 webhook 中的 data.verificationId——放在 path 中 |
Request 示例
// GET /api/v1/verifications/6f1c2a9e-4b7d-4c1e-9a52-0d3f8e7b1c24
// Authorization: Bearer s2t_live_xxxxxxxxResponse 示例
{
"success": true,
"data": {
"verificationId": "6f1c2a9e-4b7d-4c1e-9a52-0d3f8e7b1c24",
"environment": "live",
"status": "success",
"channel": "api",
"createdAt": "2026-10-14T04:20:11.512Z",
"requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c",
"qrData": "0038000600000101030060217A3828f7b4f3244ff35102TH910480CE",
"transactionRef": "A3828f7b4f3244ff3",
"amount": 100000,
"message": null,
"reason": null,
"duplicate": false,
"cached": false,
"warnings": [],
"checks": {
"stale": false,
"slipAgeHours": 0.1,
"receiver": "matched",
"receiverLabel": "บัญชีหลัก",
"amount": "matched",
"expectedAmount": 100000
},
"transfer": { "...": "与 data.transfer 相同的数据" }
},
"requestId": "9d4e2b17-5c6a-4f3e-8b1d-2a7c0e9f6b35"
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
data | object | 一条验证结果(字段见下方各行) |
…verificationId | string | 验证 ID,与验证响应及 webhook 中的 verificationId 相同 |
…environment | "live" | "test" | live = 正式结果 · test = 测试密钥的模拟结果 |
…status | "success" | "failed" | success = 银行确认凭证 · failed = 未通过或被拒绝 |
…channel | "api" | "line" | "web" | 凭证来源:api · line(店铺的 LINE 机器人)· web(后台的凭证验证页面) |
…createdAt | string | 验证时间(ISO 8601) |
…amount | number | null | 金额(泰铢)——未通过时为 null |
…reason | string | null | 请求在到达银行前被拒绝的原因或验证系统故障——null = 已由银行判定 |
…warnings | string[] | 与验证响应相同:duplicate · receiver_mismatch · amount_mismatch · stale_slip |
…checks | object | null | 与验证时相同的检查结果(stale · receiver · amount)——可能为 null |
…transfer | object | null | 转账详情,结构与验证响应中的 data.transfer 相同——未通过时为 null |
注意事项与建议
- 按验证时保存的内容返回结果,不再询问银行,也不扣配额
- 不存在或不属于您的店铺 → HTTP 404 及 reason: not_found
- 测试密钥只能看到测试结果(保留 7 天),正式密钥只能看到正式结果——使用另一类型的密钥将返回 404
- 需要 verify:slip 权限,并经过与凭证验证相同的检查(IP 白名单 · 频率限制)
按 qrData、transactionRef 或 requestId 查找店铺的验证结果——例如请求超时后,在此查询而不是重新发送凭证
Scope: verify:slip
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
qrData | string (query) | 曾发送验证的二维码内容(须完全一致 · 放入 query 前请进行 URL 编码) | |
transactionRef | string (query) | 验证结果中的交易参考号 | |
requestId | string (query) | 该次验证请求的 requestId(X-Request-Id header) | |
limit | number (query) | 最多返回条数 1–50(默认 20) |
Request 示例
// GET /api/v1/verifications?transactionRef=A3828f7b4f3244ff3&limit=5
// Authorization: Bearer s2t_live_xxxxxxxxResponse 示例
{
"success": true,
"data": [
{
"verificationId": "6f1c2a9e-4b7d-4c1e-9a52-0d3f8e7b1c24",
"environment": "live",
"status": "success",
"channel": "api",
"createdAt": "2026-10-14T04:20:11.512Z",
"requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c",
"qrData": "0038000600000101030060217A3828f7b4f3244ff35102TH910480CE",
"transactionRef": "A3828f7b4f3244ff3",
"amount": 100000,
"message": null,
"reason": null,
"duplicate": false,
"cached": false,
"warnings": [],
"checks": {
"stale": false,
"slipAgeHours": 0.1,
"receiver": "matched",
"receiverLabel": "บัญชีหลัก",
"amount": "matched",
"expectedAmount": 100000
},
"transfer": { "...": "与 data.transfer 相同的数据" }
}
],
"requestId": "1f7a3c9e-2d4b-4e8a-b6c5-9e0d1a2b3c4d"
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
data | object[] | 符合条件的结果,最新的在前——无结果时为空数组 |
…verificationId | string | 验证 ID,与验证响应及 webhook 中的 verificationId 相同 |
…environment | "live" | "test" | live = 正式结果 · test = 测试密钥的模拟结果 |
…status | "success" | "failed" | success = 银行确认凭证 · failed = 未通过或被拒绝 |
…channel | "api" | "line" | "web" | 凭证来源:api · line(店铺的 LINE 机器人)· web(后台的凭证验证页面) |
…createdAt | string | 验证时间(ISO 8601) |
…amount | number | null | 金额(泰铢)——未通过时为 null |
…reason | string | null | 请求在到达银行前被拒绝的原因或验证系统故障——null = 已由银行判定 |
…warnings | string[] | 与验证响应相同:duplicate · receiver_mismatch · amount_mismatch · stale_slip |
…checks | object | null | 与验证时相同的检查结果(stale · receiver · amount)——可能为 null |
…transfer | object | null | 转账详情,结构与验证响应中的 data.transfer 相同——未通过时为 null |
注意事项与建议
- 可同时使用多个筛选条件(须全部匹配)· 不加筛选 = 店铺最新的结果
- 最新的在前 · 无结果 = HTTP 200,data 为空数组
- 筛选条件格式错误或 limit 不在 1–50 之间 → HTTP 400 及 reason: invalid_request
- 不扣配额 · 测试密钥只能看到测试结果,正式密钥只能看到正式结果
暂未开放——所有调用都会被密钥权限检查拒绝,返回 HTTP 403 reason: service_disabled
Scope: verify:name
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
accountNumber | string | 必填 | 账号,仅填数字,不含连字符 |
bankCode | string | 必填 | 3 位银行代码,例如 014 = SCB、004 = Kasikornbank、006 = Krungthai |
Request 示例
{
"accountNumber": "1234567890",
"bankCode": "014"
}Response 示例
{
"success": true,
"message": "Account name verified",
"data": {
"accountNumber": "1234567890",
"accountName": "นาย สมชาย ใจดี",
"accountNameTh": "นาย สมชาย ใจดี",
"accountNameEn": "MR. SOMCHAI JAIDEE",
"bankCode": "014",
"bankName": "ไทยพาณิชย์",
"iconUrl": "https://raw.githubusercontent.com/casperstack/thai-banks-logo/master/icons/SCB.png"
}
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
data.accountName | string | 泰文名称,与 accountNameTh 相同,为向后兼容而保留 |
data.accountNameEn | string | 英文名称,银行未返回时可能为空 |
data.bankName | string | 与所发送 bankCode 对应的银行名称 |
data.iconUrl | string | 官方银行标志的 URL,可直接在网页中显示 |
注意事项与建议
- 此服务暂未开放——上方示例为开放后将使用的格式
- 目前所有请求都无法通过密钥权限检查,返回 HTTP 403 及 reason: service_disabled(错误格式与其他接口相同)
- bankCode 与“结果中的银行代码”部分使用同一套代码
检查密钥 · IP 白名单 · 套餐是否就绪,不验证真实凭证也不扣配额——适合首次接入时使用
Scope: verify:slip
请求参数
无需发送 Request Body,只需附带 Authorization Header:Authorization: Bearer s2t_live_xxxxxxxx
Request 示例
// GET Request Header:
// Authorization: Bearer s2t_live_xxxxxxxxResponse 示例
{
"success": true,
"message": "เชื่อมต่อสำเร็จ พร้อมตรวจสลิป",
"ready": true,
"environment": "live",
"merchant": { "code": "M0001", "name": "您的店铺" },
"apiKey": { "name": "主服务器", "keyPrefix": "s2t_live_ab12" },
"yourIp": "203.0.113.10",
"plan": { "name": "BASIC", "remainingSlips": 1850, "expiresAt": "2026-11-13T17:00:00.000Z", "expired": false },
"requestId": "e3a7c1f9-5b2d-4e8a-9c6f-1d4b7e0a3c52"
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
ready | boolean | true = 可立即发送凭证验证(测试密钥始终为 true)· false = 套餐已过期或凭证额度用完(额度模式:余额低于一次验证的费用) |
environment | "live" | "test" | live = 正式密钥 · test = 测试密钥(模拟结果,无需套餐) |
yourIp | string | 系统看到的您服务器的 IP——可直接添加到 IP 白名单 |
plan.remainingSlips | number | null | 剩余凭证数(null = 不限) |
requestId | string | 请求 ID,与 X-Request-Id 响应头相同——联系客服时附上,我们可立即找到该请求 |
注意事项与建议
- 与凭证验证经过完全相同的检查(密钥 · 店铺 · IP · 频率),可用于排查请求被拒绝的原因
- 不调用银行,也不扣除配额
- 测试密钥始终返回 environment: test 和 ready: true,即使店铺尚无套餐
商户剩余额度,可在批量发送请求前查询(无需 body,只需带上密钥 header)
Scope: verify:slip
请求参数
无需发送 Request Body,只需附带 Authorization Header:Authorization: Bearer s2t_live_xxxxxxxx
Request 示例
// GET Request Header:
// Authorization: Bearer s2t_live_xxxxxxxxResponse 示例
{
"success": true,
"environment": "live",
"balance": 1850,
"currency": "credit",
"plan": {
"name": "BASIC",
"billingMode": "package",
"remainingSlips": 1850,
"expiresAt": "2026-11-13T17:00:00.000Z"
},
"requestId": "6d0b3f8e-2a5c-4e9b-a7d1-8c4f1e6b0a27"
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
environment | "live" | "test" | live = 正式密钥 · test = 测试密钥 |
balance | number | 剩余余额——套餐模式下为仍可验证的凭证数(1 credit = 1 张凭证) |
currency | string | 单位(credit) |
plan | object | null | 当前套餐——null = 尚无套餐 |
plan.remainingSlips | number | null | 剩余凭证数(null = 不限) |
plan.expiresAt | string | null | 套餐到期时间(ISO 8601) |
requestId | string | 请求 ID,与 X-Request-Id 响应头相同——联系客服时附上,我们可立即找到该请求 |
注意事项与建议
- 无需发送 Request Body,只需附带 Authorization Header
- 需要具有 verify:slip 权限的密钥,并经过与凭证验证相同的检查(IP 白名单 · 频率限制)
- 密钥错误或已吊销时返回 HTTP 401 reason: invalid_api_key(旧字段 error: invalid api key 还会保留一个版本)
今日所有渠道(API + LINE + 网页)的验证次数和已用凭证,按泰国时间计算(无需 body,只需带上密钥 header)
Scope: verify:slip
请求参数
无需发送 Request Body,只需附带 Authorization Header:Authorization: Bearer s2t_live_xxxxxxxx
Request 示例
// GET Request Header:
// Authorization: Bearer s2t_live_xxxxxxxxResponse 示例
{
"success": true,
"environment": "live",
"today": {
"calls": 312,
"credits": 298
},
"breakdown": {
"denied": 4,
"errors": 1
},
"requestId": "0f6c9a2e-8d4b-4b1f-a3e7-5c2d9f6a1b84"
}响应中的重要字段
| 字段名 | 类型 | 含义 |
|---|---|---|
environment | "live" | "test" | live = 正式密钥(店铺的真实记录)· test = 测试密钥(仅统计测试密钥的模拟验证) |
today.calls | number | 今日所有渠道(API + LINE 机器人 + 网页)银行已判定的凭证数(通过 + 未通过)——到达银行前被拒绝的请求(无套餐 / 已过期 / 已用完等)和验证系统故障不计入 |
today.credits | number | 今日实际扣除的凭证数(验证通过且不是您店铺的重复凭证)· 测试密钥始终为 0 |
breakdown.denied | number | 今日到达银行前被拒绝的请求(如 no_plan、plan_expired、quota_exceeded、insufficient_credit、feature_disabled)——不扣凭证 |
breakdown.errors | number | 今日遇到验证系统故障的请求(返回 503 temporarily_unavailable)——不扣凭证,可重新发送 |
requestId | string | 请求 ID,与 X-Request-Id 响应头相同——联系客服时附上,我们可立即找到该请求 |
注意事项与建议
- 统计数据于每天泰国时间午夜(UTC+7)自动重置
- 未通过密钥校验的请求(401、403、429 等)不会记录为验证,因此不在任何数字中——请查看 API 调用记录页面
- 包括通过 LINE 机器人和网页凭证验证页面验证的凭证,而不只是 API · 未通过或被拒绝的凭证不会扣除 credits
- 需要具有 verify:slip 权限的密钥——密钥错误时与其他 endpoint 一样返回 HTTP 401 reason: invalid_api_key
reason 字段可帮助您的系统准确区分情况并正确提示用户
| reason 字段 | HTTP | 含义 | 处理方式 |
|---|---|---|---|
| invalid_request | 400 | 未发送 qrData 或 image(或两者都发送)、qrData 长度不在 10–1000 个字符之间、expectedAmount 无效、JSON 格式错误,或 GET /api/v1/verifications 的筛选条件无效——如有 param 字段则指明出错的字段 | 二选一发送 { "qrData": "…" } 或 { "image": "<base64>" } · expectedAmount 须大于 0 且最多 2 位小数 |
| payment_qr | 400 | 发送的是收款二维码(PromptPay / 商户二维码),而不是凭证二维码 | 请客户发送付款后的凭证,而不是用于扫码付款的二维码 |
| qr_not_found | 422 | 无法从图片中读取二维码 | 使用银行 App 中二维码清晰、未裁剪的凭证图片 |
| invalid_api_key | 401 | 缺少或格式错误的 Authorization header、密钥错误或已吊销 | 检查密钥 / 新建密钥(Bearer 不区分大小写)· 旧字段 error: invalid api key 将在下个版本移除 |
| no_plan | 402 | 店铺尚无套餐 | 购买套餐 / 领取免费试用 |
| plan_expired | 402 | 套餐已过期 | 购买新套餐 |
| quota_exceeded | 402 | 套餐内的凭证已用完 | 再购买套餐(仅当原套餐未过期时剩余凭证才会累加) |
| insufficient_credit | 402 | 额度不足(按额度计费的店铺) | 在钱包页面充值 |
| ip_not_allowed | 403 | 服务器 IP 不在 IP 白名单中 | 在 IP 白名单页面添加 IP |
| service_disabled | 403 | 该密钥或店铺无权使用此服务(例如尚未开放的 verify/name) | 使用具有 verify:slip 权限的密钥 |
| feature_disabled | 403 | 该店铺账户尚未开通凭证验证 | 联系技术支持 |
| merchant_suspended | 403 | 店铺已被停用 | 联系技术支持 |
| not_found | 404 | 您的店铺中没有该验证结果(GET /api/v1/verifications/:id)、使用了与验证时不同类型的密钥,或请求了不存在的 path | 检查 verificationId,并使用与验证时相同类型的密钥(测试 / 正式)· 测试结果保留 7 天 |
| payload_too_large | 413 | body 超过 4 MB(base64 图片请控制在约 3 MB 以内),其他 endpoint 超过 64 KB | 发送前缩小/压缩图片,或改为发送 qrData |
| unsupported_media_type | 415 | 不支持的 Content-Type,或图片不是 JPEG/PNG(WebP、GIF、HEIC、AVIF、PDF)——multipart 上传时 param 为 file | 使用 application/json、image/jpeg、image/png,或附带 JPEG/PNG 的 multipart/form-data |
| rate_limited | 429 | 超过店铺的每分钟限额(默认 120 次/分钟,正式密钥与测试密钥分别计算),或测试密钥每天验证超过 1,000 次 | 按 Retry-After 等待后重试(每分钟限额最多 60 秒 · 测试密钥每日上限为距离重置的秒数),建议在您的系统中排队发送 |
| auth_locked | 429 | 此 IP(或同一 /24 网段)1 分钟内发送无效 API 密钥超过 30 次——对无效密钥返回,正在使用的有效密钥可正常使用 · 在引入此代码之前,这种情况返回 rate_limited——如果您的代码在收到 rate_limited 时退避,请对 auth_locked 做同样处理 | 确认所有服务器都使用当前密钥(重置后的旧密钥 / 输入错误)——用同一密钥重试没有用,请按 Retry-After 等待后使用正确的密钥(如果有效密钥在同一网段大量发送错误密钥期间收到此代码,请按 Retry-After 等待后重试) |
| too_many_failed | 429 | 您的店铺今天被银行判定未通过的凭证超过 300 张 | 停止发送非真实凭证的二维码数据,并按 Retry-After(距离重置的秒数)等待 |
| internal_error | 500 | 系统意外错误 | 稍后重试(凭证验证请先查询结果再重发)· 如持续出现,请把 requestId 发给技术支持 |
| temporarily_unavailable | 503 | 银行验证系统或查询类 endpoint 的数据源暂时故障 | 按 Retry-After(5 秒)后重试——同一张凭证可再次发送 |
请让代码仅根据 success 和 reason 判断——message 为泰文且措辞可能调整,切勿用于比对
错误响应格式
/api/v1/* 的所有非 2xx 响应格式相同(reason 取值见上表)
HTTP/1.1 400 Bad Request
Content-Type: application/json
X-Request-Id: 2c9f4e1a-7b3d-4a8e-9f61-5d0c2b7a8e14
{
"success": false,
"status": "Failed",
"code": "400",
"reason": "invalid_request",
"message": "expectedAmount ต้องเป็นตัวเลขมากกว่า 0 ทศนิยมไม่เกิน 2 ตำแหน่ง",
"param": "expectedAmount",
"requestId": "2c9f4e1a-7b3d-4a8e-9f61-5d0c2b7a8e14"
}| 字段名 | 类型 | 含义 |
|---|---|---|
success | false | 始终为 false |
status | "Failed" | 始终为 Failed |
code | string | 字符串形式的 HTTP status,例如 400 |
reason | string | 上表中的原因代码——请据此区分情况 |
message | string | 供人阅读的泰文说明,措辞可能调整 |
requestId | string | 与 X-Request-Id header 相同——联系技术支持时请附上 |
param | string? | 仅在 400 参数错误时出现:出错字段的名称 |
error | string? | 仅在 401 时出现:旧值 invalid api key——再保留一个版本,请改用 reason |
被拒绝或失败的请求不占用配额
success: false,且不含 reason每分钟最多请求数,以及超出时的处理方式
- 默认每个店铺每分钟 120 次请求(可按店铺调整——当前限额见回调 / Webhook 页面),同一店铺的所有正式密钥共用(多建密钥不会增加限额)· 测试密钥单独计算(限额相同),不会占用正式密钥的额度
- 所有通过密钥校验的响应都带有
X-RateLimit-Limit·X-RateLimit-Remaining·X-RateLimit-Reset——Limit = 每分钟上限 · Remaining = 本分钟剩余次数 · Reset = 距离重新计数的秒数 - 所有使用 API Key 的 endpoint 都计入:verify/slip、verifications、ping、balance 和 usage
- 除每分钟限制外,测试密钥每个店铺每天最多验证 1,000 次
- 每个店铺每天被银行判定未通过的凭证超过 300 张时,返回 HTTP 429 reason: too_many_failed(防止乱发二维码数据)
- 超出后返回 HTTP 429,带有
reason: rate_limited和Retry-Afterheader(秒)——所有 429 和 503 都带此 header,测试密钥也一样。请等待相应时间后再重试(不扣额度) - 如需大量验证,请在您的系统中排队分批发送,收到 429 时不要立即重试
HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 37
Content-Type: application/json
{
"success": false,
"status": "Failed",
"code": "429",
"reason": "rate_limited",
"message": "ส่งคำขอถี่เกินกำหนด กรุณาลองใหม่ภายหลัง",
"requestId": "8a4d2f6c-1e9b-4c7a-b3d5-6f0e8a2c4b19"
}系统会按您在回调 / Webhook 页面选择的事件,自动将结果推送到您的 Callback URL,无需自行编写轮询代码。
推送的事件
| Event | 推送时机 |
|---|---|
| verify.success | 银行已确认凭证(包括重复凭证——见 data.duplicate) |
| verify.failed | 仅在银行判定凭证未通过时——请求被拒绝(含 reason)或系统故障时不推送 |
| credit.low | 剩余凭证/额度降至设定阈值(跨过阈值时推送一次) |
| credit.empty | 凭证/额度已用完(用完时推送一次) |
包括通过店铺 LINE 机器人验证的凭证
请求附带的 Header
POST /webhooks/verifyslips HTTP/1.1
Content-Type: application/json
User-Agent: Slip2Try-Webhook/1.0
X-VerifySlips-Event: verify.success
X-VerifySlips-Delivery: 3e5b7c1d-9a2f-4d6e-8b0c-1f4a7e2d9c63
X-VerifySlips-Signature: sha256=9f86d081884c7d65...
X-VerifySlips-Signature-Previous: sha256=7d1a54127b222502... # 用旧 Secret 的 V1 签名——仅在轮换 Secret 后 24 小时内出现
X-VerifySlips-Signature-V2: t=1789753097,sha256=4e07408562bedb8b...
X-VerifySlips-Signature-V2-Previous: t=1789753097,sha256=b5c1e9d07a3f2c84... # 仅在轮换 Secret 后 24 小时内出现(用旧 Secret 签名)
X-VerifySlips-Timestamp: 1789753097
X-VerifySlips-Test: true # 仅在通过“发送测试 webhook”按钮发送或来自测试密钥时出现X-VerifySlips-Timestamp 为发送时间(unix 秒)。X-VerifySlips-Signature-V2 的签名包含时间(${timestamp}.${body} 的 HMAC-SHA256),建议使用它,并拒绝超过 5 分钟的请求以防重放
各事件的 Body 示例
Body · verify.success
{
"id": "3e5b7c1d-9a2f-4d6e-8b0c-1f4a7e2d9c63",
"event": "verify.success",
"environment": "live",
"createdAt": "2026-10-14T04:20:11.512Z",
"channel": "api",
"requestId": "3b1f0c9e-6a2d-4f5e-8b7c-1d2e3f4a5b6c",
"transactionRef": "A3828f7b4f3244ff3",
"data": {
"verificationId": "6f1c2a9e-4b7d-4c1e-9a52-0d3f8e7b1c24",
"status": "success",
"message": null,
"amount": 100000,
"currency": "THB",
"duplicate": false,
"firstVerifiedAt": null,
"checks": {
"stale": false,
"slipAgeHours": 0.1,
"receiver": "matched",
"receiverLabel": "บัญชีหลัก",
"amount": "matched",
"expectedAmount": 100000
},
"transfer": { "...": "转账详情与 data.transfer 相同" }
}
}当您的店铺已成功验证过该凭证时 data.duplicate 为 true,data.firstVerifiedAt 为首次验证时间(不重复时为 null)
id 是本次推送的标识(重试和手动重发时保持不变——用于去重)· environment 为 live 或 test · verify.* 还包含 channel(api / line / web)和该次验证请求的 requestId(channel 不是 api 时为 null)
data.unit 为 slip(套餐模式)或 credit(额度模式)· credit.* 事件的 transactionRef 始终为 null
推送与重试
- 您的端点须在 10 秒内返回 HTTP 2xx 才算推送成功
- 返回非 2xx、超时、无法连接或重定向(3xx)均视为失败——系统不跟随重定向,请填写最终 URL
- 验证完成后立即发送第一次推送(在 API 响应返回之后——webhook 不会早于 API 响应到达)· 失败后最早在 10 秒、1 分钟、5 分钟、30 分钟和 2 小时后重试(共 6 次),之后停止。重试在有请求进入系统时(任何店铺) 或每天一次的定时任务(泰国时间 07:00)执行,因此在流量很少时每次重试最多可能延迟约 24 小时 · 不要只依赖 webhook——请用 GET /api/v1/verifications 对账,或在推送记录中手动重发
- 从后台发送的测试 body 中包含
"test": true,测试密钥产生的结果包含"environment": "test"——两者都带有 X-VerifySlips-Test: true header,且不会重试 - URL 必须以 https:// 开头且可公开访问(不接受 localhost 或内网 IP)
务必先验证 HMAC-SHA256 签名,再信任请求
建议使用 V2 标签:校验 X-VerifySlips-Signature-V2(时间戳.body 的 HMAC),并拒绝与当前时间相差超过 5 分钟的请求 · V1 标签(X-VerifySlips-Signature,仅对 body 签名)仍可用于现有系统,但无法防止重放
verify_signature_v2.js
const express = require('express');
const crypto = require('crypto');
const app = express();
const TOLERANCE_SEC = 300; // 只接受 5 分钟以内的签名
// 在回调 / Webhook 页面设置的 Secret
const SECRETS = [
process.env.VERIFYSLIPS_CALLBACK_SECRET || 'your_webhook_secret',
process.env.VERIFYSLIPS_CALLBACK_SECRET_PREVIOUS, // 切换期间的旧 Secret(可选)——切换完成后删除
].filter(Boolean);
// t=<unix>,sha256=<hex>
function validV2(header, rawBody) {
const parts = Object.fromEntries(String(header || '').split(',').map((p) => p.trim().split('=')));
const ts = parts.t || '';
// 时间过旧或在未来 → 拒绝(防重放)
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > TOLERANCE_SEC) return false;
const given = Buffer.from(String(parts.sha256 || ''));
return SECRETS.some((secret) => {
const expected = Buffer.from(crypto.createHmac('sha256', secret).update(`${ts}.`).update(rawBody).digest('hex'));
// 使用 constant-time 比较,防止 timing attack
return given.length === expected.length && crypto.timingSafeEqual(given, expected);
});
}
// 必须读取 Raw Body 才能正确计算 HMAC-SHA256
app.post('/webhooks/verifyslips', express.raw({ type: 'application/json' }), (req, res) => {
// 先校验 V2,不通过再校验 V2-Previous(轮换 Secret 后 24 小时内)
if (!validV2(req.headers['x-verifyslips-signature-v2'], req.body) && !validV2(req.headers['x-verifyslips-signature-v2-previous'], req.body)) {
return res.status(401).send('Invalid signature');
}
const payload = JSON.parse(req.body.toString('utf8'));
// 每次重试 id 都相同 → 已处理过的推送直接跳过
if (alreadyProcessed(payload.id)) return res.status(200).send('ok');
// 测试结果(environment: test)不是真实到账 → 确认接收但不发货
if (payload.environment !== 'live') return res.status(200).send('ok');
if (payload.event === 'verify.success') {
const { transactionRef, data } = payload;
const checks = data.checks || {};
if (data.duplicate) {
// 凭证已被使用(首次:data.firstVerifiedAt)→ 不要重复充值
} else if (checks.receiver === 'mismatch' || checks.amount === 'mismatch' || checks.stale) {
// 转入其他账户、金额不符或旧凭证(同 API 响应中的 warnings)→ 人工审核
} else {
console.log(`凭证验证成功: ${transactionRef} 金额: ${data.amount}`);
// TODO: 将订单标记为已付款(transactionRef 保持唯一)
}
}
// 尽快返回 200
res.status(200).send('ok');
});
app.listen(3000);轮换 Secret 与暂停发送
- 在 Webhook 页面轮换 Secret 后立即生成新 Secret——接下来 24 小时内每个 webhook 都带两个签名:用新 Secret 的
X-VerifySlips-Signature-V2和用旧 Secret 的X-VerifySlips-Signature-V2-Previous(t= 相同) - 您这边:先校验
X-VerifySlips-Signature-V2,不匹配再校验X-VerifySlips-Signature-V2-Previous——请在 24 小时内完成系统中的 Secret 更新,之后不再发送X-VerifySlips-Signature-V2-Previous - 仍在校验 V1 签名?同样的 24 小时内会随
X-VerifySlips-Signature一起发送X-VerifySlips-Signature-Previous(用旧 Secret 对 body 的 sha256=)——先校验X-VerifySlips-Signature,不匹配再校验X-VerifySlips-Signature-Previous - 可在同一页面暂停发送——暂停期间新事件不会发送,恢复后也不会补发(可用 GET /api/v1/verifications 查询历史结果)· 测试按钮和已在等待重试的记录仍会发送
1. 使用 Raw Body
在 JSON 解析之前基于 Raw Body 计算 Hash,否则结果将不匹配
2. 使用恒定时间比较
使用 hash_equals / crypto.timingSafeEqual / hmac.compare_digest,不要用 == 或 ===
3. 防止重复处理
webhook 可能重复送达(重试)——请用 body 中的
id(与X-VerifySlips-Deliveryheader 相同,重试时保持不变)作为幂等键4. 尽快返回 200
扣减库存、发送邮件等耗时任务请放入 Background Queue
用于将验证结果中的 fromBankCode / toBankCode 转换为银行名称和标志(泰国央行 3 位代码)

Bangkok Bank
BBL
002
Kasikorn Bank
KBANK
004
Krungthai Bank
KTB
006
TMBThanachart Bank
TTB
011
The Siam Commercial Bank
SCB
014
Citibank
CITI
017
CIMB Thai Bank
CIMB
022
United Overseas Bank
UOB
024
Krungsri Bank
BAY
025
Government Savings Bank
GSB
030
HSBC
HSBC
031
GH Bank
GHB
033
Bank for Agriculture and Agricultural Cooperatives
BAAC
034
Islamic Bank of Thailand
IBANK
066
Tisco Bank
TISCO
067
Kiatnakin Phatra Bank
KKP
069
ICBC (Thai)
ICBC
070
Thai Credit Bank
TCRB
071
LH Bank
LHB
073
CLICX Bank
CLICX
088
PromptPay 与电子钱包(无银行代码)
API 不会为 PromptPay 或电子钱包返回代码——收款方为这些服务时 toBankCode 可能为空,请改用返回的银行/服务名称(本站网页和 LINE 机器人按名称匹配标志)。
- 按名称匹配

PromptPay
- 按名称匹配

TrueMoney
已为您店铺开通的服务,以及无法自行解决时的联系方式
联系技术支持
请先调用 GET /api/v1/ping,并查看验证记录 / webhook 推送记录——如仍无法解决,请直接联系我们
Telegram 技术支持
@blacksteps
Discord 技术支持
discord.gg/Utr2KgzjqE
后台中的开发者工具
联系我们之前可以先自行排查——每个响应都有 requestId,可在 API 调用记录中搜索