API

从你自己的系统创建验证请求,将签名链接发送给对方,并在对方签名后获取证书。对方的操作不变:打开链接并签署一条消息,无需账户。

API 访问包含在 Pro 和 Business 套餐中。请在账户 → API 密钥中创建密钥。

身份验证

每次调用时将密钥作为 bearer token 发送。密钥仅在创建时显示一次;我们只存储其哈希值。

Authorization: Bearer signet_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

基础 URL:https://basignet.com/api/v1。机器可读的描述位于 /api/v1/openapi.json。

创建请求

curl https://basignet.com/api/v1/requests \
  -H "Authorization: Bearer $SIGNET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chain": "tron",
    "targetAddress": "TNeiUDQmrGHbsC4oPd8L6dZdxyPQrrWyP2",
    "reference": "KYC-2026-0412",
    "anchor": true,
    "messageLocale": "ru",
    "expiresAt": "2026-10-31T23:59:59Z"
  }'

只有 chain 是必填项。将 targetAddress 留空,由对方提供其签名所用的地址;填写则要求必须使用该地址。

anchor: true 会在签名后将证书锚定到链上,并在锚定时计入你的每月额度。messageLocale 设置默认消息的语言(参见“区块链与语言”);message 用你自己的文本替换消息正文。Nonce / Issued / Domain 页脚始终会附加。

响应即请求对象。请通过你自己的渠道将 signingUrl 发送给对方。

获取请求

curl https://basignet.com/api/v1/requests/{token} \
  -H "Authorization: Bearer $SIGNET_KEY"

返回请求对象。status 为 pending、failed(最近一次签名未通过验证;链接仍可使用)、verified 或 expired。验证通过后,certificate 字段会被填充。

列出请求

curl "https://basignet.com/api/v1/requests?status=verified&limit=50" \
  -H "Authorization: Bearer $SIGNET_KEY"

{ "object": "list", "data": [ …requests ], "hasMore": true, "nextBefore": "2026-09-30T10:12:03.117Z" }

按从新到旧排序。limit 取值 1 到 100(默认 20),status 用于筛选,before 接收上一页的 nextBefore 值。

证书

curl https://basignet.com/api/v1/requests/{token}/certificate \
  -H "Authorization: Bearer $SIGNET_KEY" -o proof.json

curl "https://basignet.com/api/v1/requests/{token}/certificate?format=pdf" \
  -H "Authorization: Bearer $SIGNET_KEY" -o certificate.pdf

自包含的证明包,格式为 JSON;使用 ?format=pdf 则返回 PDF。请求签名之前返回 409。证明包无需依赖我们,可使用开源验证工具验证。

区块链与语言

curl https://basignet.com/api/v1/chains

公开接口,无需密钥:支持的区块链(将 id 用作 chain)以及 messageLocale 可用的语言。

Webhook

在账户 → Webhook 中设置端点,即可接收 HTTPS POST,无需轮询:

请求体为 { id, type, created, data: { request } },其中 request 与 API 返回的对象相同。请在 5 秒内返回任意 2xx 响应。投递失败后将在 1 分钟、5 分钟、30 分钟、2、6、12 和 24 小时后重试,之后标记为失败。可使用 id 忽略重复投递。

每个 POST 都带有 Signet-Signature: t=…,v1=…:v1 是使用端点签名密钥对 t + "." + raw body 计算的十六进制 HMAC-SHA256。请在解析之前基于原始请求体进行校验,并拒绝早于几分钟之前的时间戳:

// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verifySignet(rawBody, header, secret, toleranceSec = 300) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
  const given = Buffer.from(v1, "hex");
  return given.length === expected.length && timingSafeEqual(given, expected);
}
# Python
import hmac, hashlib, time

def verify_signet(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(kv.split("=", 1) for kv in header.split(","))
    t, v1 = parts.get("t"), parts.get("v1")
    if not t or not v1 or abs(time.time() - int(t)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

错误与限制

HTTP/1.1 403
{ "error": { "type": "plan_required", "message": "API access is included in the Pro and Business plans." } }

错误以 JSON 返回:{ "error": { "type", "message" } }。类型:unauthorized(401)、plan_required(403)、not_found(404,访问其他账户的令牌时也会返回)、conflict(409)、invalid_request(400)、rate_limited(429,附带 Retry-After)。

每个密钥每分钟可调用 120 次。

请求对象

{
  "object": "request",
  "token": "q0tHA2UW6oiuuzVC1qtIf2N1dgKX6miW",
  "status": "verified",                      // pending | failed | verified | expired
  "chain": "ethereum",
  "chainLabel": "Ethereum",
  "targetAddress": null,                     // null = supplied by the signer
  "reference": "KYC-2026-0412",
  "anchor": true,
  "signingUrl": "https://basignet.com/s/q0tHA2UW6oiuuzVC1qtIf2N1dgKX6miW",
  "challenge": "BA Signet — Proof of Wallet Control\n…\nNonce: …\nIssued: …\nDomain: basignet.com",
  "createdAt": "2026-09-30T09:58:41.201Z",
  "expiresAt": null,
  "completedAt": "2026-09-30T10:03:12.554Z",
  "certificate": {                           // null until signed
    "address": "0x5e3fbf618ef1cc1cc021e7fed95e07c6ff334ca8",
    "sigType": "eip191",
    "contentHash": "0xaa00c6f6…",
    "verifiedAt": "2026-09-30T10:03:12.554Z",
    "verifyUrl": "https://basignet.com/verify/0xaa00c6f6…",
    "anchorStatus": "anchored",              // unanchored | pending | anchored
    "anchor": {                              // null until anchored
      "chain": "polygon",
      "txHash": "0x…",
      "txUrl": "https://polygonscan.com/tx/0x…",
      "blockNumber": 94660444,
      "blockTime": "2026-09-29T15:30:06.000Z",
      "merkleRoot": "0x…",
      "bitcoinBlockHeight": null
    }
  }
}

v1 内可能新增字段;现有字段不会被重命名或删除。