API
자체 시스템에서 검증 요청을 생성하고, 서명 링크를 상대방에게 보내고, 서명이 완료되면 인증서를 받으세요. 상대방의 절차는 달라지지 않습니다. 링크를 열고 계정 없이 메시지 하나에 서명하면 됩니다.
API 액세스는 Pro 및 Business에 포함됩니다. 계정 → API 키에서 키를 생성하세요.
인증
모든 호출에서 키를 bearer 토큰으로 보내세요. 키는 생성 시 한 번만 표시되며, 저희는 해시만 저장합니다.
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에 사용할 수 있는 언어를 반환합니다.
웹훅
계정 → 웹훅에서 엔드포인트를 설정하면 폴링 대신 HTTPS POST를 받을 수 있습니다:
request.verified: 상대방이 서명했고 인증서가 발급되었습니다.request.anchored: 인증서가 온체인에 앵커링되었습니다(anchor로 생성한 요청에만 해당).ping: 계정 페이지에서 보내는 테스트 이벤트입니다.
본문은 { 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를 계산한 16진수 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 내에서 필드가 추가될 수 있으며, 기존 필드의 이름이 바뀌거나 제거되지는 않습니다.