انتقل إلى المحتوى
Sekyro AI

ادمجوا التحقق في خدمتكم

رابط مستضاف دون برمجة، أو الـ API من خادمكم: اختاروا التكامل المناسب لفريقكم، واختبروه في Sandbox، ثم انتقلوا إلى Live.

مستضاف أم مدمج؟

الطرق الأربع لدمج Sekyro AI جنباً إلى جنب. ابدؤوا بأبسطها: يمكنكم إضافة طريقة أخرى لاحقاً على التطبيق نفسه.

مقارنة خيارات التكامل
المعيارالروابط المستضافةواجهة API للخادمالويب وReactiOS وAndroid
التوفرمتاحمتاحقيد التأكيدمخطط
البرمجة المطلوبةلا شيءخادمكمخادمكم وموقعكمخادمكم وتطبيقكم
أين يتحقق الشخصصفحة مستضافة من Sekyro AI تُفتح من رابطالصفحة المستضافة للجلسةداخل موقعكمداخل تطبيقكم
المنصة الواجب تسجيلهالا شيء — التطبيق دون منصة يخدم الروابط المستضافةلا شيءالويب: النطاقات المصرّح بهاiOS: ‏Team ID وbundle ID · Android: الحزمة وبصمات SHA-256
مفتاح الـ APIلا: تُنشأ الروابط في لوحة التحكمنعم، على الخادم فقطنعم، على الخادم فقطنعم، على الخادم فقط

مرّر الجدول أفقياً

من الدعوة إلى أول جلسة

مسار التكامل بالترتيب الذي تقترحه لوحة التحكم. وتبيّن كل خطوة من يمكنه تنفيذها.

  1. ادخلوا إلى لوحة التحكم

    يفتح فريق Sekyro AI مؤسستكم. يدعوكم مدير بدور محدد؛ اقبلوا الدعوة بالعنوان المدعو.

    جميع الأدوار

  2. أنشئوا تطبيقاً

    سمّوه واختاروا منصاته. يتطلب الويب نطاقات مصرّحاً بها، ويتطلب iOS وAndroid معرّفات. ودون منصة، يخدم التطبيق الـ API والروابط المستضافة.

    مديرمطوّر

  3. اختاروا ملف eKYC

    انطلقوا من ملف بداية وراجعوا معاينة الخطوات. ويتوقف الوصول إلى السجل على صلاحيات مؤسستكم.

    مديرمطوّر

  4. أنشئوا مفتاح Sandbox

    ينشئ المدير مفتاح التطبيق. ولا يُعرض السرّ إلا مرة واحدة: انسخوه إلى مدير الأسرار لديكم.

    مدير

  5. أنشئوا جلسة اختبار

    عبر البدء السريع أدناه أو رابط مستضاف، ثم افحصوا الجلسة — والمراجعة إن وُجدت — في لوحة التحكم.

    مديرمطوّر

  6. استعدّوا لـ Live

    حين تُفتح بيئة Live لمؤسستكم، أنشئوا مفتاح Live واستبدلوا به مفتاح Sandbox على الخادم.

    مدير

أول جلسة لكم باستدعاء واحد

أنشئوا جلسة من خادمكم بمفتاح Sandbox الخاص بتطبيقكم.

  • يبقى المفتاح على الخادم: لا يوضع أبداً في صفحة ويب ولا في تطبيق جوال.
  • المفتاح الذي يبدأ بـ sk_test_ يعمل في Sandbox، و sk_live_ في Live.
  • ينقل متن الطلب رقم التعريف الوطني حين يستخدم الملف السجل.
الدليل الكامل للبدء السريع
إنشاء جلسةserver-create.ts
// Next.js Server Actions (App Router) backed by @sekyro/node.
//
// Two jobs live on YOUR server, never in the browser:
//   1. startVerification — create a session BOUND to the user's NNI and hand
//      the page nothing but the one-time client token.
//   2. decideVerification — read the authoritative session and decide.
//
// The API key is a server secret. The client token is the end user's flow
// credential: returned once by `sessions.create`, never logged, never stored
// in a cookie or URL.
"use server";

import { Sekyro, SekyroApiError, type Session } from "@sekyro/node";

const sekyro = new Sekyro({
  apiKey: requireEnv("SEKYRO_API_KEY"),
  // Production is the default. For the sandbox set
  // SEKYRO_API_BASE_URL=https://api-staging.sekyro.ai/api/v2 with an sk_test_ key.
  baseUrl: process.env.SEKYRO_API_BASE_URL ?? "https://api.sekyro.ai/api/v2",
});

export interface StartVerificationResult {
  sessionId: string;
  /** Hand this to the page (`createVerification({ clientToken })`). Returned ONCE. */
  clientToken: string;
  /** ISO 8601 — the capture must finish before this. */
  expiresAt: string;
}

/**
 * Create a session bound to `nni`. The browser never sends the NNI: the SDK
 * submits `population_registry` with an empty input and the server uses the
 * bound value (a browser that sends a DIFFERENT nni gets 409 `nni_locked`).
 *
 * `attempt` is your own counter per user: the idempotency key makes a network
 * retry of the SAME attempt return the SAME session instead of minting two.
 */
export async function startVerification(
  userId: string,
  nni: string,
  attempt: number,
): Promise<StartVerificationResult> {
  try {
    const created = await sekyro.sessions.create(
      // No recipe here: the API key belongs to an app, and the app's eKYC
      // profile decides the steps (e.g. population_registry → liveness →
      // face_match for the "Mauritania: registry" profile).
      { locale: "ar", input: { nni } },
      { idempotencyKey: `kyc:${userId}:${attempt}` },
    );
    // Persist the id BEFORE returning: the webhook can arrive before the page
    // reports back, and your handler must be able to find the user by session.
    await saveSessionId(userId, created.id);
    return {
      sessionId: created.id,
      clientToken: created.clientToken,
      expiresAt: created.expiresAt,
    };
  } catch (err) {
    if (err instanceof SekyroApiError) {
      // `retryable` covers network, timeout, 429, 5xx and idempotency_in_progress:
      // back off and call again with the SAME idempotencyKey.
      throw new Error(
        `Sekyro AI ${err.code} (request ${err.requestId ?? "n/a"}), retryable=${err.retryable}`,
      );
    }
    throw err;
  }
}

export type Decision = "approved" | "rejected" | "pending" | "expired";

export interface DecideResult {
  decision: Decision;
  session: Session;
}

/**
 * The ONLY place a verdict is decided. Call it when the page reports
 * `onResult`, and again from your webhook handler on async transitions.
 */
export async function decideVerification(sessionId: string): Promise<DecideResult> {
  const session = await sekyro.sessions.get(sessionId);
  return { decision: decide(session), session };
}

function decide(session: Session): Decision {
  switch (session.status) {
    case "completed":
      // `outcome` is `approved | review | rejected`; `review` here means a
      // human decided the session is complete but flagged — treat as pending
      // until your own policy says otherwise.
      if (session.outcome === "approved") return "approved";
      if (session.outcome === "rejected") return "rejected";
      return "pending";
    case "failed":
      return "rejected";
    case "review_pending":
      // Parked for human review (up to 48 h). Wait for `session.review_decided`.
      return "pending";
    case "expired":
      // The user did not finish in time: offer a new session.
      return "expired";
    case "created":
    case "in_progress":
      return "pending";
  }
}

function requireEnv(name: string): string {
  const value = process.env[name];
  if (value === undefined || value === "") throw new Error(`${name} is not set`);
  return value;
}

// Replace with your database write.
async function saveSessionId(_userId: string, _sessionId: string): Promise<void> {}

الوصول إلى لوحة التحكم

لديكم وصول بالفعل؟ سجّلوا الدخول عبر Ibtikar ID لإدارة تطبيقاتكم ومفاتيحكم وجلساتكم.

ليس لديكم وصول بعد؟ تحصل عليه مؤسستكم من فريق Sekyro AI، ثم يدعوكم أحد المديرين.

لنتحدّث عن مسار التحقق الخاص بكم

صِفوا خدمتكم والأشخاص الذين تحتاجون إلى التحقق من هوياتهم. يساعدكم فريق Sekyro AI على اختيار طريقة التكامل ويفتح لكم الوصول إلى Sandbox.