快速開始
跑通"列出虛擬卡卡頭"是驗證鑑權鏈路最快的方式(無副作用、不需要冪等鍵)。
1. 準備憑證
透過使用者控制台生成一對憑證:
APP_ID:cp_+ 28 位 hex 字元(共 31 字元)SECRET:64 位 hex 字元
妥善保管
SECRET 僅在生成時返回一次,丟失只能 reset。建議儲存到金鑰管理服務(KMS / Vault / GCP Secret Manager)。
2. 複製下面的指令碼
bash
APP_ID="cp_a1b2c3d4..."
SECRET="f1e2d3c4..."
BASE="https://api.coinepay.net"
PATH_VAL="/api/v1/openapi/card_headers/list"
BODY='{"page":1,"page_size":20}'
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -hex | awk '{print $2}')
SIGN_INPUT=$(printf 'POST\n%s\n\n%s\n%s\n%s' "$PATH_VAL" "$TS" "$NONCE" "$BODY_HASH")
SIG=$(echo -n "$SIGN_INPUT" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')
curl -X POST "$BASE$PATH_VAL" \
-H "X-App-Id: $APP_ID" \
-H "X-Timestamp: $TS" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIG" \
-H "Content-Type: application/json" \
-d "$BODY"python
import time, hmac, hashlib, secrets, json, requests
APP_ID = "cp_a1b2c3d4..."
SECRET = "f1e2d3c4..."
BASE = "https://api.coinepay.net"
PATH = "/api/v1/openapi/card_headers/list"
BODY = json.dumps({"page": 1, "page_size": 20}, separators=(",", ":")).encode()
ts = str(int(time.time()))
nonce = secrets.token_hex(16)
body_hash = hashlib.sha256(BODY).hexdigest()
sign_input = f"POST\n{PATH}\n\n{ts}\n{nonce}\n{body_hash}"
sig = hmac.new(SECRET.encode(), sign_input.encode(), hashlib.sha256).hexdigest()
r = requests.post(BASE + PATH, headers={
"X-App-Id": APP_ID, "X-Timestamp": ts, "X-Nonce": nonce, "X-Signature": sig,
"Content-Type": "application/json",
}, data=BODY)
print(r.json())js
import crypto from 'node:crypto'
const APP_ID = 'cp_a1b2c3d4...'
const SECRET = 'f1e2d3c4...'
const BASE = 'https://api.coinepay.net'
const PATH = '/api/v1/openapi/card_headers/list'
const body = JSON.stringify({ page: 1, page_size: 20 })
const ts = Math.floor(Date.now() / 1000).toString()
const nonce = crypto.randomBytes(16).toString('hex')
const bodyHash = crypto.createHash('sha256').update(body).digest('hex')
const signInput = `POST\n${PATH}\n\n${ts}\n${nonce}\n${bodyHash}`
const sig = crypto.createHmac('sha256', SECRET).update(signInput).digest('hex')
const res = await fetch(BASE + PATH, {
method: 'POST',
headers: {
'X-App-Id': APP_ID, 'X-Timestamp': ts, 'X-Nonce': nonce, 'X-Signature': sig,
'Content-Type': 'application/json',
},
body,
})
console.log(await res.json())3. 期望響應
json
{
"code": 200,
"message": "成功",
"data": {
"list": [
{
"header_id": "hdr_5",
"card_bin": "424242",
"card_brand": "VISA",
"card_area": "美國",
"business_scene": "境外消費",
"description": { "zh-CN": "適合電商訂閱", "en-US": "For e-commerce subscriptions" },
"features": ["3DS", "EMV"],
"require_phone": false,
"require_email": true
}
],
"total": 12,
"page": 1,
"page_size": 20,
"total_pages": 1,
"has_next": false,
"has_prev": false
}
}4. 完整開卡流程
5. 常見錯誤
| 現象 | 原因 |
|---|---|
| 401 invalid_credentials | 簽名錯 / 時間戳過期 / nonce 重放 / AppID 不存在 |
| 400 openapi_idempotency_key_required | 寫介面未傳 Idempotency-Key 頭 |
| 409 openapi_idempotency_key_conflict | 同 key 不同 body |
| 429 | 觸發限流(600 次/分鐘) |
詳見 錯誤碼字典。
下一步
- HMAC 鑑權 — 把簽名規範讀完,避免奇怪的 401
- Webhook 規範 — 接收開卡完成等非同步事件
- 程式碼樣例 — Python / Go / Java / PHP 完整客戶端