Skip to content

查詢卡片資訊

預設返回卡的狀態、餘額、脫敏卡號

當請求體傳 with_sensitive=true 時,同一介面會在響應裡額外返回 完整 PAN / CVV / 到期日 / 持卡人姓名,授權方式二選一:

  1. 使用者二次驗證(預設可用,自助) —— 與 Web 端檢視 CVV 完全一致:按賬戶配置的交易認證方式提交 email_code / pin / two_fa_code / sms_code。驗證碼透過 /openapi/card/sensitive/send_code 獲取,無需管理員審批。
  2. 憑證免驗證特權(需審批) —— 面向全自動 server-to-server 場景,憑證可被授予免二次驗證特權。預設關閉 —— 詳見下文 敏感卡片資訊

常用於:

  • 非同步開卡後輪詢,直到 status=2 (active)
  • 業務側定期同步餘額
  • 排查 webhook 是否漏投遞
  • 在自有收銀臺 / 錢包 UI 中展示 PAN / CVV(兩條授權路徑均可)

端點

MethodPOST
Path/api/v1/openapi/card/info
鑑權HMAC
冪等鍵不需要

請求欄位

欄位型別必填說明
card_idstringcard_<id> 格式
with_sensitivebool可選true 表示請求完整 PAN / CVV / 到期日 / 持卡人姓名。預設 false。需卡片為 active,且透過兩條授權路徑之一。
email_codestring條件必填郵箱驗證碼(賬戶交易認證方式含郵箱時必填)。透過 /openapi/card/sensitive/send_code 傳送。免驗證特權憑證無需傳。
sms_codestring條件必填簡訊驗證碼(認證方式含簡訊時必填)。
pinstring條件必填交易 PIN 碼(認證方式含 PIN 時必填;使用者在 Web 端設定)。
two_fa_codestring條件必填2FA / Google Authenticator 動態碼(認證方式含 2FA 時必填)。

請求示例 — 預設(僅狀態與餘額)

json
{ "card_id": "card_12345" }

請求示例 — 請求敏感欄位(使用者二次驗證路徑)

json
{
  "card_id": "card_12345",
  "with_sensitive": true,
  "email_code": "482913"
}

請求示例 — 請求敏感欄位(免驗證特權憑證)

json
{
  "card_id": "card_12345",
  "with_sensitive": true
}

響應欄位

始終返回

欄位型別說明
card_idstring回顯
card_typestring全小寫:virtual_l / virtual_p / virtual_v / virtual_r / virtual_g / virtual_a
card_brandstring卡組織
currencystring卡內幣種
statusint1=pending 2=active 3=failed 4=closing 5=closed 6=frozen
status_descstring英文描述
masked_card_nostring脫敏卡號(前 6 後 4),如 424242******1234
last_fourstring卡號末 4 位
balancestring (decimal)卡內可用餘額
frozen_balancestring (decimal)卡內凍結餘額
activated_atstring nullable啟用時間(成功後才有)
created_atstring建立時間

僅當 with_sensitive=true、授權透過、且 status=2 時返回

欄位型別說明
card_numberstring完整 PAN(無空格 / 無橫線)
cvvstring卡安全碼(Visa / Mastercard 為 3 位)
expiry_datestring到期日,格式 MM/YY
first_namestring持卡人名(開卡時提供)
last_namestring持卡人姓

任一前提不滿足時,這些欄位會整體省略(不存在、不為 null 也不為空串)。

響應示例 — 預設

json
{
  "code": 200,
  "message": "成功",
  "data": {
    "card_id": "card_12345",
    "card_type": "virtual_v",
    "card_brand": "VISA",
    "currency": "USD",
    "status": 2,
    "status_desc": "active",
    "masked_card_no": "424242******1234",
    "last_four": "1234",
    "balance": "85.50",
    "frozen_balance": "0",
    "activated_at": "2026-04-29T11:00:30Z",
    "created_at": "2026-04-29T11:00:12Z"
  }
}

響應示例 — 含敏感欄位

json
{
  "code": 200,
  "message": "成功",
  "data": {
    "card_id": "card_12345",
    "card_type": "virtual_v",
    "card_brand": "VISA",
    "currency": "USD",
    "status": 2,
    "status_desc": "active",
    "masked_card_no": "424242******1234",
    "last_four": "1234",
    "balance": "85.50",
    "frozen_balance": "0",
    "activated_at": "2026-04-29T11:00:30Z",
    "created_at": "2026-04-29T11:00:12Z",
    "card_number": "4242420000001234",
    "cvv": "123",
    "expiry_date": "12/28",
    "first_name": "JOHN",
    "last_name": "DOE"
  }
}

狀態碼(status)

含義說明
1pending開卡中
2active已啟用,可用
3failed開卡失敗(終態)
4closing銷卡中
5closed已銷卡(終態)
6frozen已凍結(使用者 / 風控)

敏感卡片資訊

敏感欄位(card_number / cvv / expiry_date / first_name / last_name)受兩條授權路徑之一保護:

路徑適用物件每次請求需要開通方式
A. 使用者二次驗證所有憑證(預設)按賬戶交易認證配置提交 email_code / pin / two_fa_code / sms_code —— 僅在信任視窗外需要(見下)無需開通 —— 自助可用
B. 憑證免驗證特權審批透過的對接方無(不需要驗證碼)需管理員審批,預設關閉

路徑 A 與 Web 端使用同一套交易認證配置(安全設定 → 交易認證)、同一驗證用途、同樣的一次性驗證碼。路徑 B 面向無人值守的 server-to-server 自動化 —— 該場景下無法每次請求都由人完成二次驗證。

信任視窗 —— 驗證一次,視窗內免驗證

透過本介面成功完成一次二次驗證後,賬戶進入信任視窗(時長由平臺管理員配置,預設 30 分鐘0 = 關閉)。視窗生效期間,再次對自己名下的卡發起 with_sensitive=true 請求無需攜帶任何驗證欄位即可成功 —— 一次人工驗證後即可程式化批次獲取多張卡的 PAN/CVV(例如把卡分發給下游使用者的場景)。

  • 視窗為固定視窗,不滑動:從驗證成功時刻起算,視窗內的免驗請求不會續期;到期需重新驗證。
  • 視窗按賬戶維度生效,覆蓋該憑證名下所有卡。
  • 視窗生效期間 send_code 返回 grace_active=true 且不發碼 —— 對接方可低成本探測當前是否需要驗證碼。注意:視窗外呼叫會實際發碼並佔用 60 秒冷卻,請勿把它當作無副作用的狀態探針輪詢。
  • 管理員封禁始終凌駕於信任視窗之上。

路徑 A — 使用者二次驗證(預設)

第一步:傳送驗證碼

MethodPOST
Path/api/v1/openapi/card/sensitive/send_code
鑑權HMAC
冪等鍵不需要
請求體{}(空 JSON 物件)
冷卻同一賬戶 60 秒內限 1 次 → 超頻返回 429 + Retry-After

驗證用途由服務端固定(get_card_sensitive)—— 本介面不能用於觸發轉賬、提現等其他操作的驗證碼,其他用途的驗證碼在這裡也不被接受。

響應 data

欄位型別說明
require_emailbool第二步需提交 email_code
require_smsbool第二步需提交 sms_code
require_pinbool第二步需提交 pin(不發碼 —— PIN 由使用者本人持有)
require_2fabool第二步需提交 two_fa_code(不發碼 —— 由認證器 App 生成)
email_sentbool6 位驗證碼已傳送至賬戶繫結郵箱
sms_sentbool6 位驗證碼已傳送至賬戶繫結手機
grace_activebool信任視窗生效中:不發碼、不消耗冷卻 —— 跳過第二步的驗證欄位直接調 /card/info

如果賬戶只使用 PIN 和/或 2FA,則不會傳送任何驗證碼(email_sent=false, sms_sent=false)且不消耗冷卻視窗 —— 直接攜帶本地因子進入第二步。

第二步:攜帶驗證碼呼叫 /card/info

with_sensitive=true,並附上第一步響應中標記為需要的所有欄位。驗證碼特性:

  • 一次性 —— 驗證透過即消費;每次驗證都需重新發碼(信任視窗生效期間無需驗證)
  • 限時 —— 10 分鐘內有效
  • 防爆破 —— 連續輸錯會臨時鎖定驗證(返回 429

驗證成功即開啟信任視窗 —— 視窗內的後續獲取完全無需驗證欄位。

路徑 B — 憑證免驗證特權(需審批)

預設關閉 — 需顯式審批後開通

免驗證特權對每一份 API 憑證預設關閉,且受平臺級總開關額外保護。如需開通,請聯絡你的客戶經理或提交工單。開通時需要:

  • 說明業務用途(如無法引入人工二次驗證的無人值守自動化)
  • 確認你的環境符合 PCI-DSS 對 PAN 儲存 / 展示的要求
  • 提供你的 AppIDcp_xxxx...),授權將下發到正確的憑證

憑證開關與平臺開關均為 ON 時,with_sensitive=true 無需任何驗證碼欄位即可成功。免驗證特權憑證仍可攜帶驗證碼欄位 —— 會被忽略。

訪問前提

下列四個條件必須同時滿足,敏感欄位才會下發:

  1. 請求 — 呼叫方顯式傳 with_sensitive: true
  2. 授權 — 有效的使用者二次驗證憑據(路徑 A)憑證具備免驗證特權(路徑 B)
  3. 卡狀態 — 卡必須處於 status=2 (active)pending / failed / closing / closed / frozen 一律拒絕
  4. 無管理員封禁 — 平臺管理員可按卡或按賬戶維度強制關閉敏感資訊獲取。封禁同時壓制兩條授權路徑(驗證碼正確、免驗證特權憑證均無效),返回 403 card_sensitive_access_banned;賬戶維度封禁同時攔截 send_code。如認為封禁有誤請聯絡客服。

任一不滿足,響應為 403(驗證被鎖定時為 429)加對應的 message_key。欄位不會部分返回 —— 單次請求是"全有或全無"。

合規與處理建議

把返回的 PAN 視為高敏感 PCI 資料

  • 不要日誌:完整 card_number / cvv 不要寫到應用日誌或 APM
  • 不要落庫:PAN / CVV 不要持久化到自有資料庫或分析數倉
  • 僅透過 TLS 透傳到你的前端,渲染後立即丟棄
  • 非展示狀態下務必脫敏;優先使用 masked_card_no
  • 一旦懷疑憑證洩漏,立即在使用者後臺 Reset OpenAPI Secret

運維說明

  • 免驗證特權(路徑 B)可被回收。一旦被回收,後續不帶驗證碼的 with_sensitive=true 請求將在 ~5 分鐘內(快取傳播視窗)失效 —— 之後自動落入路徑 A,返回對應的 *_required key。
  • 這些 403 錯誤碼與鑑權中介軟體返回的 401 不同 —— 403 表示鑑權透過但二次驗證缺失/未透過,或卡狀態拒絕敏感訪問。
  • 此介面絕會透過 webhook payload 推送敏感欄位;敏感欄位只能透過本同步介面獲取。

典型錯誤

HTTPmessage_key說明
400openapi_invalid_card_id卡 ID 錯誤
400openapi_card_type_not_supported對非虛擬卡型別請求敏感欄位
401openapi_invalid_credentials鑑權失敗
403email_code_required / sms_code_required / pin_required / 2fa_code_required傳了 with_sensitive=true 但缺對應的二次驗證欄位(且憑證無免驗證特權)。先呼叫 send_code 再重試。
403invalid_email_code / invalid_sms_code / invalid_pin / invalid_2fa_code提交的二次驗證憑據錯誤或已過期
403email_not_verified / phone_not_verified / no_usable_auth_method賬戶對應驗證渠道不可用 —— 請在 Web 端完善安全設定
403card_sensitive_access_banned該卡或該賬戶的敏感資訊獲取已被管理員強制關閉,任何授權路徑均無效
403openapi_sensitive_card_only_active卡不在 status=2 (active),敏感欄位拒絕下發
404card_not_found卡不存在 / 不屬於當前賬號
429too_many_requests驗證連續失敗被臨時鎖定(或 PIN 鎖定);請遵循 Retry-After
500openapi_get_card_info_failed服務端異常
500openapi_internal_error載入憑證上下文失敗

/card/sensitive/send_code 的錯誤:

HTTPmessage_key說明
401openapi_invalid_credentials鑑權失敗
403card_sensitive_access_banned該賬戶的敏感資訊獲取已被管理員強制關閉,不傳送驗證碼
429too_many_requests發碼冷卻中(同一賬戶 60 秒 1 次);請遵循 Retry-After
500send_code_failed傳送失敗 —— 冷卻已釋放,可立即重試

推薦輪詢策略

python
import time

def wait_card_active(card_id, max_minutes=10):
    """非同步開卡後輪詢,直到 active 或失敗"""
    deadline = time.time() + max_minutes * 60
    backoff = 2
    while time.time() < deadline:
        info = call("/api/v1/openapi/card/info", {"card_id": card_id})
        status = info['data']['status']
        if status == 2:
            return info['data']  # active
        if status in (3, 5):
            raise CardOpenFailed(info['data'])
        time.sleep(backoff)
        backoff = min(backoff * 2, 30)  # 指數退避,最多 30 秒
    raise TimeoutError(f"Card {card_id} not active in {max_minutes} min")


def fetch_pan_for_display(card_id, email_code=None, sms_code=None, pin=None, two_fa_code=None):
    """一次性拿敏感欄位渲染前端,絕不落庫。

    路徑 A(預設):先 POST /openapi/card/sensitive/send_code,向賬戶所有人
    收集所需二次驗證憑據後傳入本函式。
    路徑 B(免驗證特權憑證):不傳任何驗證碼直接呼叫。
    """
    body = {"card_id": card_id, "with_sensitive": True}
    for k, v in {"email_code": email_code, "sms_code": sms_code,
                 "pin": pin, "two_fa_code": two_fa_code}.items():
        if v:
            body[k] = v
    resp = call("/api/v1/openapi/card/info", body)
    if resp.get('code') == 403:
        key = resp.get('message_key')
        if key and key.endswith('_required'):
            raise PermissionError(f"缺少二次驗證憑據:{key} —— "
                                  "請先呼叫 /openapi/card/sensitive/send_code")
        if key and key.startswith('invalid_'):
            raise PermissionError(f"二次驗證未透過:{key}")
        if key == 'openapi_sensitive_card_only_active':
            raise RuntimeError("卡未啟用,敏感欄位暫不可獲取")
    if resp.get('code') == 429:
        raise RuntimeError("驗證已鎖定,請按 Retry-After 時間後重試")
    if resp.get('code') != 200:
        raise RuntimeError(f"獲取卡資訊失敗:{resp.get('message_key')}")
    return resp['data']  # 含 card_number / cvv / expiry_date / first_name / last_name


def request_sensitive_code():
    """路徑 A 第一步:觸發郵箱/簡訊驗證碼,並獲知需要哪些驗證因子"""
    resp = call("/api/v1/openapi/card/sensitive/send_code", {})
    if resp.get('code') != 200:
        raise RuntimeError(f"發碼失敗:{resp.get('message_key')}")
    return resp['data']  # require_email / require_sms / require_pin / require_2fa / email_sent / sms_sent

優先用 webhook

能用 webhook 就用 webhook。card/info 輪詢是 fallback —— 僅用於 webhook 接收器臨時不可用、或對賬場景。

採用 MIT 等價條款釋出