SDK
Python API SDK
瞭解如何在 Python 專案中安裝和設定 StableOps API SDK,安全讀取金鑰與環境設定,建立和查詢付款訂單,管理收款地址及 Webhook,並正確使用冪等鍵、超時、重試和異常處理,將穩定幣支付接入後端服務。
安裝
pip install stableops要求 Python 3.8+,依賴 httpx 與 pydantic v2。同時提供同步 StableOps
與非同步 AsyncStableOps 兩套用戶端,API 形狀一致。
想看可執行的完整示例?
Playground 在瀏覽器裡串起「建單 → 錢包支付 → 確認 → finalized」全流程,並附帶可閱讀的原始碼。
設定
import os
from stableops import StableOps
client = StableOps(
api_key=os.environ["STABLEOPS_API_KEY"],
# 可選項:
# base_url="https://api.stableops.dev",
# timeout=30.0,
# max_retries=2,
# checkout_base_url="https://pay.stableops.dev", # 僅影響 checkout url 拼接
)環境(sandbox / live)由 API Key 字首(sk_sandbox_… / sk_live_…)決定,無需額外參數。
非同步用法:
import asyncio
from datetime import datetime, timedelta, timezone
from stableops import AsyncStableOps
async def main() -> None:
async with AsyncStableOps(api_key="sk_sandbox_...") as client:
order = await client.payment_orders.create(
merchant_order_id="sub_89231_2026_06",
amount="49.00",
accepted_assets=[{"chain": "base", "asset": "USDC"}],
expires_at=(datetime.now(timezone.utc) + timedelta(minutes=30)).isoformat(),
)
print(order.id)
asyncio.run(main())付款訂單
from datetime import datetime, timedelta, timezone
order = client.payment_orders.create(
merchant_order_id="sub_89231_2026_06",
amount="49.00",
accepted_assets=[
{"chain": "base", "asset": "USDC"},
{"chain": "tron", "asset": "USDT"},
],
# 30 分鐘後未支付自動過期,訂單進入 expired 並釋放地址。
expires_at=(datetime.now(timezone.utc) + timedelta(minutes=30)).isoformat(),
# 可選:'auto' 讓伺服器端把金額微調到唯一(SHARED 地址免手動錯開金額)。
amount_mode="auto",
)
client.payment_orders.retrieve(order.id)
client.payment_orders.list(status="detected", limit=50)
client.payment_orders.cancel(order.id)merchant_order_id 同時作為冪等鍵:worker 重試時落到同一記錄,不會重複建單。
amount 是人類可讀的十進位制字串(例如 "49.00"),應保持字串形式或使用
Decimal 處理,不要用 float(amount)。requested_amount 為
商戶傳入的基準金額(auto 單為微調前金額,用於對帳)。
Checkout Sessions(託管結帳頁)
checkout_sessions.create 返回一個託管支付頁(WalletConnect),把使用者跳轉到 session.url 即可。
from datetime import datetime, timedelta, timezone
session = client.checkout_sessions.create(
merchant_order_id="sub_89231_2026_06",
amount="49.00",
accepted_assets=[{"chain": "base", "asset": "USDC"}],
expires_at=(datetime.now(timezone.utc) + timedelta(minutes=30)).isoformat(),
title="Pro 方案",
success_url="https://your-app.example.com/pay/success",
cancel_url="https://your-app.example.com/pay/cancel",
)
print(session.url) # 跳轉使用者到此連結完成支付Webhook 端點
endpoint = client.webhooks.create_endpoint(
url="https://your-app.example.com/hooks/stableops",
enabled_events=["payment.detected", "payment.confirmed", "payment.finalized"],
# 可選:投遞 payload 中剔除訂單 metadata。
redact_metadata=True,
)
endpoints = client.webhooks.list_endpoints()
client.webhooks.update_endpoint(endpoint.id, description="生產環境")
# endpoint.secret 只在建立/輪換時出現一次,請妥善儲存。
client.webhooks.rotate_secret(endpoint.id)投遞與重放
# 列出投遞記錄(可按狀態 / 端點 / 訂單過濾)。
deliveries = client.webhooks.list_deliveries(status="failed", limit=20)
# 把某個事件重新投遞到指定端點。
client.webhooks.replay(endpoint.id, event_id)
# 重放單條投遞。
client.webhooks.replay_delivery(delivery_id)
# 批次重放死信。
result = client.webhooks.replay_dead_letters(endpoint_id=endpoint.id, limit=100)
print(result.replayed)Webhook 驗籤
在你的回呼處理函式里校驗簽名(以 Flask 為例):
from stableops import SIGNATURE_HEADER, verify_webhook_signature
@app.route("/hooks/stableops", methods=["POST"])
def handle_webhook():
body = request.get_data(as_text=True)
result = verify_webhook_signature(
body=body,
header=request.headers.get(SIGNATURE_HEADER),
secret=os.environ["STABLEOPS_WEBHOOK_SECRET"],
)
if not result.valid:
return {"error": result.reason}, 401
# 用原始 body(不要先 json 化再回寫)做驗籤。
...
return "", 204輪換金鑰期間可傳 secrets=[old, new] 同時接受多個金鑰。
錯誤
所有非 2xx 都會拋 StableOpsError,帶 .status / .code / .message / .details。
from datetime import datetime, timedelta, timezone
from stableops import StableOpsError
try:
client.payment_orders.create(
merchant_order_id="sub_89231_2026_06",
amount="49.00",
accepted_assets=[{"chain": "base", "asset": "USDC"}],
expires_at=(datetime.now(timezone.utc) + timedelta(minutes=30)).isoformat(),
)
except StableOpsError as err:
if err.status == 409:
# 冪等鍵被相同 key 不同 body 複用
...
raise網路錯誤(超時 / 連線失敗)也會包成 StableOpsError,此時 status == 0。
這篇文件怎麼樣?
最後更新