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، أو ملف PDF باستخدام ?format=pdf. تُعاد الاستجابة 409 إلى أن يُوقَّع الطلب. يمكن التحقق من الحزمة دون الاعتماد علينا، باستخدام أداة التحقق مفتوحة المصدر.

سلاسل الكتل واللغات

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

عام، دون الحاجة إلى مفتاح: سلاسل الكتل المدعومة (تُستخدم قيمة id كقيمة chain) واللغات المتاحة لـ messageLocale.

إشعارات Webhook

تُضبط نقطة نهاية من الحساب → إشعارات Webhook لاستلام طلب HTTPS POST بدلًا من الاستعلام الدوري:

المتن هو { id, type, created, data: { request } }، حيث request هو الكائن نفسه الذي يُعيده API. يجب الرد بأي رمز 2xx خلال 5 ثوانٍ. تُعاد محاولة عمليات التسليم الفاشلة بعد دقيقة واحدة، و5 دقائق، و30 دقيقة، وساعتين، و6 و12 و24 ساعة، ثم تُعلَّم بأنها فاشلة. يُستخدم id لتجاهل التكرارات.

يحمل كل POST الترويسة Signet-Signature: t=…,v1=…: قيمة v1 هي HMAC-SHA256 بالترميز الست عشري لـ t + "." + raw body باستخدام سر التوقيع الخاص بنقطة النهاية. يجب التحقق منها على المتن الخام قبل التحليل، ورفض الطوابع الزمنية الأقدم من بضع دقائق:

// 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؛ ولا تُعاد تسمية الحقول الحالية ولا تُزال.