跳轉至

帳戶端點

取得餘額

取得帳戶的錢包和 Vault 合併餘額。

GET /balances

身份驗證: 需要 API Key

查詢參數

參數 類型 必填 說明
owner_address address 是 必須與已驗證的 API key 擁有者相符
include_zero boolean 否 預設 false:過濾普通零餘額記錄,但保留有恢復、同步或限制狀態的零餘額記錄。true 包含全部白名單代幣。

回應

{
  "owner_address": "0x...",
  "balances": [
    {
      "token": "0x965d4b4546716e416e950bc30467d128455d2d0e",
      "symbol": "USDC",
      "decimals": 6,
      "wallet_balance": "1250000000",
      "vault_available": "400000000",
      "vault_frozen": "100000000",
      "vault_total": "500000000",
      "total": "1750000000",
      "chain_verified": null,
      "spendability_status": null,
      "restriction_reason": null,
      "recovery_status": null,
      "projection_present": null,
      "recovery_version": null,
      "balance_sync_hint": null,
      "coverage_block_number": null,
      "coverage_block_hash": null,
      "coverage_checked_at": null,
      "verification_status": null,
      "generation": null,
      "snapshot_block_number": null,
      "snapshot_block_hash": null,
      "snapshot_policy_digest": null,
      "projection_updated_at": null,
      "vault_spendable": null
    }
  ],
  "updated_at": "2026-04-15T09:12:34.567890+00:00",
  "wallet_balance_available": true,
  "vault_balance_available": true
}
欄位 類型 說明
token address ERC-20 合約地址
symbol string 代幣代號
decimals integer 該代幣的精度,用於將原始字串轉成人類可讀值
wallet_balance string 使用者錢包餘額(原始 uint256 十進位字串)
vault_available string 已提交帳務的可用餘額,不一定可花(原始 uint256 字串)。
vault_frozen string Vault 中凍結在未完成訂單中的餘額(原始 uint256 十進位字串)
vault_total string vault_available + vault_frozen
total string wallet_balance + vault_total
wallet_balance_available boolean 如果錢包餘額 RPC 呼叫失敗則為 false

金額欄位為原始 uint256 十進位字串,使用 decimals 換算;可花資格與鏈上觀察可用性需要分別判斷。

可交易金額與恢復狀態

vault_spendable 非 null 時表示本次回傳的可花金額。vault_available 是已提交帳務中的可用金額;恢復或限制期間它可以大於零,而 vault_spendable 為 "0"。餘額讀取不授權下單,最終准入仍會重新檢查資格。舊版餘額模式下新增的逐資產狀態欄位可以為 null;不能把 null 當成零或資格證明。

欄位 類型 含義
vault_spendable string / null 資格檢查後的原始可花金額;帳務餘額為正時仍可能為零。
spendability_status string / null 可花資格狀態,包括 ready、local_covered、restricted、sync_required、current_coverage_required。
restriction_reason string / null 限制原因;未回報原因時為 null。
recovery_status string / null 恢復狀態,包括 ready、pending、draining、recovering、proven、blocked。
projection_present boolean / null 是否存在該資產的已提交帳務投影。
recovery_version string / null 不透明恢復版本;同步時傳入目前值。
balance_sync_hint string / null none:未觀察到差異;check_required:鏈上與帳務有差異;unknown:缺少新鮮鏈上觀察。它不是花費授權。
coverage_block_number / coverage_block_hash integer / string / null 目前覆蓋證據的區塊識別。
coverage_checked_at string / null 覆蓋核驗的 ISO 時間;讀取快取不會延長此證明的有效期。
verification_status string / null 帳務快照驗證狀態,例如 verified 或 unverified;不能單獨決定可否花費。
generation integer / null 帳務快照代次。
snapshot_block_number / snapshot_block_hash integer / string / null 帳務快照對應的區塊識別。
snapshot_policy_digest string / null 快照關聯的策略摘要。
projection_updated_at string / null 帳務投影更新的 ISO 時間;不是鏈頂或本次核驗時間。

外層 vault_balance_available 表示 Vault 鏈上觀察是否可用且新鮮,即使 balances=[] 也有意義;它不同於快照 verification_status。local_covered 行可能已有可花金額,但歷史 verification_status="unverified"。projection_updated_at 不代表證明的新鮮度。遇到未知狀態應重新整理,不能假定資金可花。

例如 vault_available="400000000"、vault_spendable="0"、spendability_status="restricted"、recovery_status="recovering" 可以同時成立。恢復狀態為 pending/draining/recovering/proven/blocked、資格為 restricted/sync_required/current_coverage_required、balance_sync_hint="check_required",或已有投影且同步提示為 unknown 時,零餘額行仍會保留。恢復流程見餘額同步。

範例

import requests

balances = requests.get(
    "https://api.testnet.sera.cx/api/v1/balances",
    params={"owner_address": "0x..."},
    headers={"Authorization": "Bearer sera_key:secret"},
    timeout=10,
).json()["balances"]

for bal in balances:
    print(f"{bal['symbol']}: available={bal['vault_available']}, frozen={bal['vault_frozen']}")
const response = await fetch(
  "https://api.testnet.sera.cx/api/v1/balances?owner_address=0x...",
  { headers: { "Authorization": "Bearer sera_key:secret" } },
);
const { balances } = await response.json();

for (const bal of balances) {
  console.log(`${bal.symbol}: available=${bal.vault_available}, frozen=${bal.vault_frozen}`);
}

請求餘額同步

POST /api/v1/balances/sync
POST /api/v2/balances/sync

身份驗證: 需要 API Key,owner_address 必須屬於該 Key。先讀取 GET /api/v1/config → capabilities.balances.sync_enabled。這是帳務同步請求,不是充值或付款。

請求

{
  "owner_address": "0x1111111111111111111111111111111111111111",
  "token_address": "0x965d4b4546716e416e950bc30467d128455d2d0e",
  "expected_recovery_version": null
}

owner_address 與 token_address 為 0x 前綴的 20 位元組十六進位地址字串,會正規化為小寫。三個欄位均必填,拒絕額外欄位。先查詢餘額,將該資產的 recovery_version 作為 expected_recovery_version:沒有版本時明確傳 null,否則傳 64 位小寫十六進位字串。不能省略或自行產生版本。

回應

HTTP 202:

{
  "status": "queued",
  "recovery_status": "pending",
  "recovery_version": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}

status 為 queued 或 already_pending;recovery_status 為 pending、draining、recovering 或 proven。輪詢 GET balances 查看進度和可花資格;202 與 proven 本身不授權交易。不要為解決同步延遲而重複充值。

HTTP detail.code / 處理
400 unknown_token:使用登錄表中的代幣
409 balance_sync_unavailable:目前部署不接受同步
409 balance_recovery_blocked:查看回傳原因及餘額狀態,不要盲目重試
409 balance_sync_version_changed:重新查詢餘額,再決定是否用目前版本重試

錯誤可能帶可為空的 detail.recovery_version 與 detail.reason:vault_below_frozen、frozen_reservation_differs、chain_event_conflict、chain_snapshot_integrity_error 或 account_recovery_blocked。還需處理 401/403、422、429 和通用 503。屬於 transfer 限流組(目前 2 req/s)。回應未知時先查詢餘額再重試;完成對帳前保留已提交版本。

充值輔助端點

請先透過 GET /config 取得目前的 vault_address 與 sor_address。現在的充值流程使用三個輔助端點:

  1. 若不使用 permit,先呼叫 POST /approve 建構 ERC-20 授權交易。
  2. 呼叫 POST /deposit 建構 depositFund(...) 或 depositFundWithPermit(...)。
  3. 本地簽名後,透過 POST /tx/send 廣播授權或充值交易。

如果代幣支援 EIP-2612,您可以在 POST /deposit 中直接傳入 permit_signature 與 permit_deadline,從而跳過單獨的授權交易。若需要在客戶端探測 permit 能力,請使用 GET /permit/metadata。

充值與提款可用性

顯示操作前讀取 /config:capabilities.deposits.enabled、.deposits.restriction_reason、.withdrawals.instant_enabled 與 .balances.sync_enabled。充值記帳暫停時,/deposit 及 /tx/send 的充值分支回傳 409、detail.code="deposit_accounting_paused",包括已簽名但尚未廣播的充值。不要建立另一筆充值,應等待能力恢復。此守衛不表示 /tx/send 的 approve 分支也被同樣拒絕。

建構充值交易

POST /deposit

身份驗證: 需要 API Key

請求主體

{
  "token": "0x965d4b4546716e416e950bc30467d128455d2d0e",
  "owner": "0x...",
  "amount": "1000000000",
  "permit_signature": "0x...",
  "permit_deadline": 1713254400,
  "permit_amount": "1000000000"
}
欄位 類型 必填 說明
token address 是 要充值的 ERC-20 代幣地址
owner address 是 充值人地址,必須與已驗證 API Key 的擁有者相符
amount string 是 原始 uint256 代幣數量
permit_signature hex string 否 用於內聯授權的 EIP-2612 permit 簽名;支援標準 65 位元組與緊湊 64 位元組兩種十六進位編碼
permit_deadline integer 否 permit 中簽名使用的截止時間
permit_amount string 否 permit 的原始授權額度;省略時預設等於 amount

未提供 permit 欄位時,建構器會產生 depositFund(token, owner, amount);提供 permit 欄位時,則會改為產生 depositFundWithPermit(...)。

回應

{
  "tx": {
    "to": "0x83475A1bD98a8DC2DCd507A747e4DC85da241D6e",
    "data": "0x...",
    "value": "0x0",
    "chainId": "0xaa36a7",
    "nonce": "0x2b",
    "gas": "0x13880",
    "type": "0x2",
    "maxFeePerGas": "0x...",
    "maxPriorityFeePerGas": "0x..."
  }
}

建構授權交易

POST /approve

身份驗證: 需要 API Key

請求主體

{
  "token": "0x965d4b4546716e416e950bc30467d128455d2d0e",
  "owner": "0x...",
  "spender": "0x3c7945840bAE0d7e7f3824Ebccef1962629250F0",
  "amount": "1000000000"
}

spender 只能是 GET /config 回傳的即時 Vault 或 SOR 地址;其他目標都會被拒絕。

回應

{
  "tx": {
    "to": "0x965d4b4546716e416e950bc30467d128455d2d0e",
    "data": "0x...",
    "value": "0x0",
    "chainId": "0xaa36a7",
    "nonce": "0x2a",
    "gas": "0xc350",
    "type": "0x2",
    "maxFeePerGas": "0x...",
    "maxPriorityFeePerGas": "0x..."
  }
}

廣播已簽名的授權或充值交易

POST /tx/send

身份驗證: 需要 API Key

請求主體

{
  "raw_tx": "0x..."
}

回應

{
  "tx_hash": "0x..."
}

POST /tx/send 只接受函式選擇器與目標地址組合位於允許清單內的已簽名授權 / 充值交易。

對於 approve,編碼後的 spender 還必須是 GET /config 回傳的即時 Vault 或 SOR 地址。如果提交的是 EIP-7702 的 type-4 交易,則每個授權 delegate 都必須位於當前部署的允許清單內,否則請求會被拒絕。


提取(共簽名)

請求伺服器共簽名以進行即時提取。Sera 的智慧合約要求即時提取需要兩個簽名 — 您的簽名和伺服器的簽名 — 以防止未經授權的提取。這是一個三步驟流程:取得共簽名、建構交易、然後廣播。

第一步:取得伺服器共簽名

POST /withdraw

身份驗證: EIP-712 WithdrawIntent 簽名

請求主體

{
  "intent": {
    "user": "0x...",
    "tokens": ["0x965d4b4546716e416e950bc30467d128455d2d0e"],
    "amounts": ["1000000000"],
    "recipient": "0x...",
    "deadline": "1704153600",
    "uuid": "123456789"
  },
  "user_signature": "0x..."
}
欄位 類型 說明
intent.user address 提取使用者的錢包
intent.tokens address[] 要提取的代幣地址(1-20)
intent.amounts string[] 每種代幣的金額(原始單位)
intent.recipient address 代幣接收地址
intent.deadline string Unix 秒數的 uint256 字串。POST /withdraw 要求在未來且最多領先 600 秒;請讀取 GET /config 的 limits.withdraw.cosignature_max_ttl_seconds。
intent.uuid string 用於防止重放的唯一識別碼(uint256 字串)
user_signature string EIP-712 WithdrawIntent 簽名

tokens 與 amounts 長度必須相等,且包含 1 至 20 項;每個 amount 必須為正 uint256 字串。

回應

{
  "success": true,
  "executor_address": "0x...",
  "executor_signature": "0x...",
  "error": null
}

第二步:建構提取交易

POST /withdraw/build

身份驗證: 可選

請求主體

{
  "intent": {
    "user": "0x...",
    "tokens": ["0x965d4b4546716e416e950bc30467d128455d2d0e"],
    "amounts": ["1000000000"],
    "recipient": "0x...",
    "deadline": "1704153600",
    "uuid": "123456789"
  },
  "user_signature": "0x...",
  "executor": "0x...",
  "executor_signature": "0x..."
}
欄位 類型 說明
intent object 與第一步相同的 WithdrawIntent
user_signature string 您的 EIP-712 簽名
executor address 第一步回應中的聯合簽名地址 executor_address
executor_signature string 第一步取得的伺服器共簽名

回應

{
  "tx": {
    "to": "0x...",
    "data": "0x...",
    "value": "0x0",
    "chainId": "0xaa36a7",
    "nonce": "0x2c",
    "gas": "0x249f0",
    "type": "0x2",
    "maxFeePerGas": "0x...",
    "maxPriorityFeePerGas": "0x..."
  }
}

第三步:廣播已簽名交易

POST /withdraw/send

身份驗證: 可選

請求主體

{
  "raw_tx": "0x..."
}

回應

{
  "tx_hash": "0x..."
}

POST /withdraw/send 只接受呼叫 executeInstantWithdrawDualSig(...) 且目標合約為來自 GET /config 的當前 Sera 合約地址的已簽名交易。如果提交的是 EIP-7702 的 type-4 交易,則每個授權 delegate 都必須位於當前部署的允許清單內,否則請求會被拒絕。

使用錢包簽署第二步的交易,然後將已簽名的十六進位提交到此端點。


緊急提取

API 不可用時,可使用 Sera 的鏈上兩步流程:

  1. 調用 emergencyWithdraw(token, amount) 發起請求,金額須為正且不超過當前 Vault 餘額。
  2. 至少等待 7,200 個區塊(按每塊 12 秒估算約 24 小時)。
  3. 在請求區塊 + 7,200 至 + 14,400(含邊界)執行,使用相同代幣及 0 < amount <= 請求金額,當前餘額仍須足夠。
  4. 成功後會刪除整個請求,即使只提取部分金額。超過 14,400 區塊窗口後,再次調用會創建新請求並重新等待。

完整規則見 Sera.sol 合約參考。

ERC-20 轉帳

無需自己的 RPC 連線即可建構和廣播 ERC-20 代幣轉帳。僅接受 /tokens 註冊表中列出的代幣。

建構轉帳

POST /transfer

身份驗證: 需要 API Key

請求主體

{
  "token": "0x965d4b4546716e416e950bc30467d128455d2d0e",
  "to": "0x...",
  "amount": "1000000000",
  "from_address": "0x..."
}
欄位 類型 必填 說明
token address 是 ERC-20 代幣合約地址(必須在代幣註冊表中)
to address 是 接收者地址
amount string 是 以原始代幣單位表示的金額
from_address address 是 發送者錢包地址

回應

{
  "tx": {
    "to": "0x...",
    "data": "0x...",
    "value": "0x0",
    "chainId": "0xaa36a7",
    "nonce": "0x2d",
    "gas": "0xea60",
    "type": "0x2",
    "maxFeePerGas": "0x...",
    "maxPriorityFeePerGas": "0x..."
  }
}

廣播轉帳

POST /transfer/send

身份驗證: 需要 API Key

請求主體

{
  "raw_tx": "0x..."
}
欄位 類型 必填 說明
raw_tx string 是 已簽名的交易十六進位(0x 前綴)

回應

{
  "tx_hash": "0x..."
}

餘額覈驗與提款錯誤

chain_verified=true 描述舊版模式對快取 Vault 金額的鏈上糾正,不能概括已提交帳務的驗證狀態;請結合上方狀態欄位。null 不代表剛完成核驗。分別檢查 wallet_balance_available、vault_balance_available 與 updated_at。

GET /api/v2/balances 是相同查詢參數與回應的別名。所有餘額金額均爲 raw 整數字串。

POST /withdraw 同時回傳 executor_address 和 executor_signature,構建 /withdraw/build 時必須把該地址作爲 executor 傳入。聯合簽名截止時間最多領先 600 秒,即使通用簽名意圖模型允許更長時間。409 且 detail.error_code="WITHDRAW_UNAVAILABLE" 表示即時提款准入拒絕,請刷新餘額/訂單後再決定是否重試。受保護賬戶操作還可能回傳 COMPLIANCE_BLOCKED。

交易簽名與廣播規則

  • POST /transfer 要求 from_address 與 API Key 所有者一致。/transfer/send 只接受向已登記代幣合約調用 transfer(...),原始交易簽名者也必須是該所有者。
  • /tx/send 同樣要求外層交易簽名者與 API Key 所有者一致;充值 calldata 中的 owner 也必須一致。充值 permit 在廣播前會重新檢查代幣、Vault spender、金額、當前 nonce 與 deadline;過時的 permit 需要重新獲取元數據並簽名。
  • /withdraw/send 要求原始交易簽名者等於 intent.user,不能替換爲第三方付費者。若攜帶 API Key,所有者也必須一致。廣播前會再次篩查用戶與接收方。
  • 構建接口回傳未簽名交易。回傳 tx_hash 表示提交給 RPC,不表示已成功打包或餘額已最終變化;請檢查交易收據並刷新餘額。