SPay OGP Agent API 對接文件

給 OGP:如何以 Agent API v1 建立與查詢入款(Deposit)、出款(Withdrawal)訂單,同步 HOUSE 卡,簽章請求,以及接收 SPay 的訂單結果 callback。

概要

環境

下表為各環境的 base URL;端點路徑接在 base URL 之後,例如 {baseUrl}/v1/agentApi/depositOrder/assign。每個環境使用各自的 API key/secret。

環境base URL
DEVhttps://spay4api.ogp99.xyz
UAThttps://spay4api.ogp88.xyz
PRDhttps://spay4api.ogp77.xyz

請求簽章

Header

Header內容
X-Api-KeySPay 交付的 API key。
X-Timestamp送出時的 Unix epoch 秒數(十進位整數,不含小數)。與 SPay 伺服器時間相差須在 ±300 秒內(含 300 秒)。
X-Nonce每個請求新產生的小寫 UUID v4,例如 123e4567-e89b-42d3-a456-426614174000。同一組 key 用過的 nonce 會被拒絕,所有端點共用。
X-SignatureHMAC-SHA256 的 64 字元十六進位字串(建議小寫);不接受 Base64。
Content-TypePOST/PUT 必須是 application/json(charset 省略或 UTF-8)。

簽章字串

METHOD + "\n" + PATH + "\n" + X-Timestamp + "\n" + X-Nonce + "\n" + BODY

時間與 nonce

回應格式

成功時 HTTP 200,body 為:

{"code":2000,"message":"","data":{...}}

失敗時 code 為錯誤碼,message 為英文短訊,data 為欄位與原因(例如 ["amount"] 或 ["payerBankCode","unknown, inactive, or out of scope"])、空陣列或 null。認證失敗為 HTTP 401、code 40000;Withdrawal 端點會先檢查 query string、body 大小與 Content-Type,不合法時回 HTTP 400、code 40005(見錯誤碼)。Deposit 與 HOUSE 卡端點的 401 body 為 {"code":40000,"message":"no authentication"}(沒有 data),Withdrawal 端點的 401 另含 "data":null。請以 HTTP status 與 code 判斷,不要比對 message 文字。

金額一律以字串表示。回應中的金額會去掉尾端的 0,例如請求 "1000.00",回應為 "1000"。時間為 ISO-8601 UTC。

Deposit

建立:POST {baseUrl}/v1/agentApi/depositOrder/assign

建立入款訂單並取得收款帳戶。Body 為 JSON object,不接受未列出的欄位、重複欄位或型別轉換。

欄位型別必填規則
agentOrderIdstring是OGP 訂單編號,1 到 100 字元;不得含控制字元、前後空白或 / \ ? #;區分大小寫。
amountstring是正數十進位字串,必須有小數點與 1 到 10 位小數,例如 "1000.00";不接受 JSON number、正負號、指數或前導 0。
payerBankCodestring是付款人銀行代碼,1 到 50 字元;須為 SPay 對此 Agent 開放的銀行。
payerAccountstring是付款人帳號,1 到 100 字元。
payerNamestring是付款人姓名,1 到 255 字元。
preferredPaymentChannelCodestring 或 null否請省略或填 null;填入非空值會被拒絕。
idempotencyKeystring是此訂單的冪等鍵,1 到 160 字元,規則同 agentOrderId。

回應 data:

欄位說明
orderNoSPay 訂單編號(32 字元十六進位)。
agentOrderId原樣回傳。
orderStatus見訂單狀態。
amount/actualAmount申請金額;實際入帳金額(完成前為 null)。
currencyCodeAgent 的幣別代碼。
expireTime付款期限(UTC);沒有收款帳戶時為 null。
paymentAccount付款人應轉入的帳戶 {bankCode, bankName, accountNumber, accountName, ownership},ownership 為 HOUSE 或 CARDHOLDER;沒有可用帳戶時為 null。
failureCode需人工審核時的原因代碼,例如 NO_ELIGIBLE_RECEIVER;其餘為 null。
requestedPaymentChannelCode、assignedPaymentChannelCode、paymentChannel、failureCategory、failureReason保留欄位,目前固定為 null。

沒有可用收款帳戶時,請求仍然成功:訂單以 PENDING_REVIEW 建立,failureCode 說明原因,paymentAccount 為 null,由 SPay 營運人員處理。

查詢:GET {baseUrl}/v1/agentApi/depositOrder/{agentOrderId}

回傳訂單目前狀態,欄位同建立回應。agentOrderId 以 UTF-8 百分比編碼放在 path,簽章使用送出的編碼後 path。找不到或不屬於此 Agent 的訂單回 HTTP 404、code 40002。

Withdrawal

建立:POST {baseUrl}/v1/agentApi/withdrawalOrder

欄位型別必填規則
agentOrderIdstring是OGP 訂單編號,1 到 100 字元,不得空白或含控制字元;原樣比對,不去除空白。
amountstring是格式同 Deposit;並須在 SPay 設定的單筆出款上下限內(含邊界),上下限由 SPay Operator 告知。
receiverBankCodestring是收款銀行代碼,1 到 50 字元;須為 SPay 對此 Agent 開放的銀行。
receiverAccountstring是收款帳號,1 到 100 個英數字(A-Z a-z 0-9)。
receiverNamestring是收款人姓名,1 到 255 字元。
preferredPaymentChannelCodestring 或 null否省略或 null 由 SPay 選擇;指定時須為 SPay 對此 Agent 開放的通道代碼,否則 HTTP 422、code 40024。
idempotencyKeystring是此訂單的冪等鍵,1 到 100 字元,規則同 agentOrderId。

欄位格式錯誤或金額超出上下限回 HTTP 422、code 40005;銀行代碼不可用回 HTTP 400、code 40005。

回應 data:orderNo、agentOrderId、orderStatus、amount、actualAmount(完成前為 null)、currencyCode、receiverBankCode、receiverBankName、receiverAccount(遮罩,只顯示末 4 碼)、receiverName(遮罩,只顯示首字)、failureCategory、failureCode、failureReason(固定 null)。需人工處理時 failureCategory 為 ROUTING,failureCode 為原因代碼,例如 NO_ELIGIBLE_ACCOUNT、INSUFFICIENT_AVAILABLE_BALANCE、REJECT_REQUEST、FROZEN_ACCOUNT、ASSIGNMENT_EXPIRED。

沒有可用出款帳戶或可用餘額不足時,請求仍然成功:訂單以 PENDING_REVIEW 建立並附原因代碼,不會以錯誤碼回應。

查詢:GET {baseUrl}/v1/agentApi/withdrawalOrder/{agentOrderId}

agentOrderId 須以 UTF-8 標準百分比編碼放在 path(例如空白寫成 %20),且不得含 / 或 \;編碼方式不同會被當成認證失敗(HTTP 401)。

以識別碼查詢:GET {baseUrl}/v1/agentApi/withdrawalOrder/byIdentity/{token}

token 是 agentOrderId 的 UTF-8 bytes 做 Base64url、不補 =,例如 OGP-W-001 為 T0dQLVctMDAx。agentOrderId 含空白、/ 等字元時請用此端點。

兩種查詢都回傳訂單目前狀態,欄位同建立回應;找不到或不屬於此 Agent 的訂單回 HTTP 404、code 40029。Withdrawal 端點的所有回應都帶 Cache-Control: no-store。

冪等與重送

訂單狀態

Deposit

orderStatus說明終態Callback
ASSIGNED已指派收款帳戶,等待付款。否
PENDING_REVIEW需 SPay 營運人員處理。否
COMPLETED入款完成。是DEPOSIT_COMPLETED
EXPIRED逾期未付款。是DEPOSIT_EXPIRED
REJECTED入款被拒絕。是DEPOSIT_REJECTED
CANCELLED訂單取消。是DEPOSIT_CANCELLED

Withdrawal

orderStatus說明終態Callback
ASSIGNED已指派出款帳戶。否
PROCESSING出款處理中。否
PENDING_VERIFICATION已提交轉帳證明,等待確認。否
PENDING_REVIEW需 SPay 營運人員處理。否
COMPLETED出款完成。是WITHDRAWAL_COMPLETED
REJECTED拒絕,未轉帳。是WITHDRAWAL_REJECTED

非終態可能直接進入任一終態;請以終態 callback 或查詢結果為準,不要假設中間狀態一定出現。

Callback

請求

SPay 對 OGP 設定的 HTTPS callback 網址送出 POST(HTTP/1.1,不跟隨 redirect),body 為 JSON:

欄位說明
eventId事件識別碼(UUID),同一事件的每次送達都相同;以此去重。
eventTypeDEPOSIT_COMPLETED、DEPOSIT_EXPIRED、DEPOSIT_REJECTED、DEPOSIT_CANCELLED、WITHDRAWAL_COMPLETED、WITHDRAWAL_REJECTED。
occurredAt終態發生時間(UTC,例如 2026-10-07T10:31:00Z)。
orderTypeDEPOSIT 或 WITHDRAWAL。
orderNo、agentOrderIdSPay 與 OGP 的訂單編號。
orderStatus終態,見訂單狀態。
amount、actualAmount申請金額;實際金額(非完成的終態可能為 null)。字串。
currency幣別代碼。
failureCategory、failureCode、failureReason保留欄位,目前固定為 null。

請以欄位名稱解析 JSON,不依賴欄位順序或空白。Header:

Header內容
X-Spay-Key-Id目前生效的 API key(與 OGP 呼叫 SPay 用的 X-Api-Key 相同)。
X-Spay-Event-Id同 body 的 eventId。
X-Spay-Event-Type同 body 的 eventType。
X-Spay-Callback-Id此次送達的識別碼,每次送達都不同;只供排查,不用於去重。
X-Spay-Timestamp此次送達的 Unix epoch 秒數。
X-Spay-Nonce此次送達新產生的小寫 UUID v4。
X-Spay-SignatureHMAC-SHA256 的 64 字元小寫十六進位。

驗章

"SPAY-CALLBACK-V1\n" + "POST\n" + PATH + "\n" + X-Spay-Timestamp + "\n" + X-Spay-Nonce + "\n" + X-Spay-Event-Id + "\n" + BODY

接收端參數(兩端聯測前約定):

參數值
Callback X-Spay-Timestamp 容許誤差300 秒
Callback X-Spay-Nonce 去重保留時間300 秒

ACK

處理成功,或該 eventId 先前已處理過,都請回:

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8

OK

只有 HTTP 2xx 且 body 精確等於大寫 OK(不含換行、空白或引號)才算送達。204、空 body、小寫 ok、JSON 或其他文字都視為失敗並重送。每次送達的總時限為 20 秒(含 DNS、連線、TLS 與回應);請先持久化事件,再回 ACK,不要在 ACK 前執行耗時處理。

重送與補送

HOUSE 卡同步

新增或更新:PUT {baseUrl}/v1/agentApi/houseCard

以 agentCardId 識別 OGP 管理的 HOUSE 卡:不存在時建立,存在時以本次內容覆蓋;內容與現況相同時不做任何變更。每次都要送完整的 8 個欄位。

欄位型別規則
agentCardIdstringOGP 的卡片識別碼,1 到 64 個 A-Z a-z 0-9 _ -,區分大小寫。
bankCodestring銀行代碼;建立時須為 SPay 對此 Agent 開放的銀行;建立後不可變更。
accountNumberstring帳號,可含英數字、空白、-、_;SPay 去除空白、-、_ 並轉大寫後保存(1 到 100 字元);建立後不可變更。
accountNamestring戶名,1 到 100 字元,不含控制字元。
displayNamestring顯示名稱,規則同 accountName。
depositEnabledboolean是否用於入款。
withdrawalEnabledboolean是否用於出款。
cardStatusstringACTIVE 或 INACTIVE。不提供刪除;停用請改為 INACTIVE。

回應 data 為該卡片:上述欄位(accountNumber 為保存後的完整帳號),另加 bankName、bankEligible(目前是否可用)與 bankEligibilityReason(不可用的原因:BANK_REFERENCE_MISSING、BANK_DELETED、BANK_INACTIVE、BANK_AGENT_MAPPING_MISSING、BANK_CURRENCY_MISMATCH,可用時為 null)。

查詢:GET {baseUrl}/v1/agentApi/houseCard

回傳此 Agent 所有由 OGP 管理的卡片(含 INACTIVE),data 為陣列,沒有分頁或篩選。

錯誤碼

HTTPcode說明處理方式
400/42240005欄位格式或內容不合法,訂單未建立;data 指出欄位。Withdrawal 建立的欄位格式錯誤與金額超出上下限為 422,其餘為 400。Withdrawal 端點帶 query string、body 超過 1 MiB、Content-Type 不符或 GET 帶 body 也回 400,data 為 null。修正請求後重送。
40140000認證失敗:header 缺漏或格式錯誤、時間超出 ±300 秒、nonce 重複、key 無效或已輪替、簽章不符,或端點不存在;Deposit 與 HOUSE 卡端點帶 query string、body 超過 1 MiB、Content-Type 不符或 GET 帶 body 也回 401。檢查簽章與時鐘,以新的 nonce 重送。
40140001Agent 目前不可使用此 API。聯絡 SPay Operator。
40440002查無 Deposit 訂單。確認 agentOrderId 與環境。
40440029查無 Withdrawal 訂單。確認 agentOrderId 與環境。
40940007HOUSE 卡的銀行與帳號已有另一張 ACTIVE 卡。先停用另一張卡。
40940045冪等鍵衝突:同一 idempotencyKey 用於另一訂單,或同一訂單內容不同。以原 body 重送,或改用新的訂單與冪等鍵。
40940046同一 agentOrderId 已以另一個 idempotencyKey 建立。以查詢端點確認既有訂單。
42240024指定的出款通道不可用。省略 preferredPaymentChannelCode 或改用可用通道。
50040048SPay 端出款設定異常。聯絡 SPay Operator。
50340044SPay 依賴服務暫時無法使用。稍後以新的 nonce 重送。
5005000SPay 內部錯誤。稍後重送;建立請求以原 body 重送不會重複建單。

簽章範例

以下為公開測試向量,secret 只用於核對實作,不能呼叫任何環境。範例程式 examples/sign-ogp-request.mjs(Node.js 18 以上)可執行 --self-test 核對兩組向量,也能對實際請求產生 header。

請求

secretogp-public-test-only
METHODPOST
PATH/v1/agentApi/depositOrder/assign
X-Timestamp1785168000
X-Nonce123e4567-e89b-42d3-a456-426614174000
BODY{"agentOrderId":"OGP-D-0001","amount":"1000.00","payerBankCode":"012","payerAccount":"1234567890","payerName":"王小明","idempotencyKey":"9f0c3d2e-OGP-D-0001"}
X-Signature83412ad5c23e239dc0db0797820b70f7afc074258ec8eaf4d236c123e123b5af

Callback

secretogp-public-test-only
PATH/ogp/spay/callback
X-Spay-Timestamp1785168060
X-Spay-Nonce0b6e2f4a-3c1d-4e5f-9a8b-7c6d5e4f3a2b
X-Spay-Event-Id019fa1f0-9a10-7c4b-8a91-1234567890ab
BODY{"eventId":"019fa1f0-9a10-7c4b-8a91-1234567890ab","eventType":"DEPOSIT_COMPLETED","occurredAt":"2026-10-07T10:31:00Z","orderType":"DEPOSIT","orderNo":"0f1e2d3c4b5a69788796a5b4c3d2e1f0","agentOrderId":"OGP-D-0001","orderStatus":"COMPLETED","amount":"1000","actualAmount":"1000","currency":"TWD","failureCategory":null,"failureCode":null,"failureReason":null}
X-Spay-Signatured836a8b4752e717edee67ca010e821ba93ebbdecbfebd3350b1d0396539a8a5f

上線注意事項