واجهة التكامل API v1

    روابط مختصرة وأسرار، من الكود مباشرة

    مفتاح bearer واحد و JSON بسيط، وقواعد الخطة نفسها المطبقة في لوحة التحكم. صُممت للإضافات وأدوات CLI وخوادم MCP والأدوات الداخلية.

    إنشاء مفتاح APIمواصفات OpenAPI

    وصول مبكر. نفعّل نقاط النهاية في الإصدار v1 مساحة عمل تلو الأخرى. إذا أعاد الطلب 503 مع الرمز disabled، فالواجهة لم تُفعَّل لك بعد. يمكنك إنشاء المفاتيح اليوم، وستعمل فور تفعيلها.

    مكتبات العملاء

    تُشفَّر الأسرار قبل إرسالها، لذا على كل عميل أن يتولى هذا الجزء بنفسه. تتولاه هذه المكتبات مرة واحدة وبالشكل الصحيح، وتُختبر على متجهات الاختبار المعتمدة نفسها التي يستخدمها تطبيق الويب. المكتبات الثلاث مرخصة بترخيص MIT، وتُنشر من CI مع إثبات المصدر في npm، ولا تعتمد إلا على المكتبة القياسية.

    TypeScript SDK

    npm

    عميل بأنواع محددة لكل مسار. بلا أي اعتماديات، ويستخدم WebCrypto فقط، فيعمل دون تعديل على Node 20+ و Deno و Bun والمتصفحات وبيئات التشغيل على خوادم الحافة.

    npm i @uselinkpilot/sdk

    سطر الأوامر

    npm

    مرّر السر عبر الأنبوب (pipe) بدل تمريره وسيطًا: الوسيط يُحفظ في سجل أوامر الصدفة ويظهر في قائمة العمليات.

    npm i -g linkpilot
    echo 'db password: hunter2' | linkpilot secret --ttl 1h

    خادم MCP

    npm

    يتيح لمساعد ذكاء اصطناعي أن يسلّم أحدًا بيانات الدخول دون أن يضعها في سجل المحادثة. أضف ما يلي إلى Claude Desktop أو Claude Code أو Cursor أو أي عميل MCP:

    {
      "mcpServers": {
        "linkpilot": {
          "command": "npx",
          "args": ["-y", "@uselinkpilot/mcp"],
          "env": { "LINKPILOT_API_KEY": "lp_live_..." }
        }
      }
    }

    اعرف هذا قبل التثبيت: النص الأصلي يمر عبر سياق المساعد، لأن النموذج يجب أن يرى السر حتى ينشئه. تحميه هذه الطريقة أثناء النقل وأثناء التخزين، وتجعل الرابط يُفتح مرة واحدة فقط، لكنها لا تستطيع إخفاءه عن النموذج نفسه.

    الكود المصدري: linkpilot-cli (SDK و CLI) و linkpilot-mcp.

    1. المصادقة

    أنشئ مفتاحًا من /app/api-keys (لمالكي مساحة العمل ومسؤوليها). يظهر المفتاح الكامل مرة واحدة، ولا تحتفظ خدمة LinkPilot إلا بقيمة تجزئة SHA-256 للمفتاح. أرسله مع كل طلب:

    Authorization: Bearer lp_live_...

    يرتبط كل مفتاح بمساحة عمل، فلا يوجد معامل tenant في أي مكان. المفاتيح المُبطلة والمنتهية الصلاحية وغير المعروفة والمشوهة تعيد كلها الاستجابة نفسها 401 unauthorized. ولا تُكتب المفاتيح في السجلات أبدًا.

    عنوان URL الأساسي: https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1

    2. المسارات

    الطريقةالمسارما يفعله
    GET/meمساحة العمل والخطة والحدود والاستهلاك وحصة الطلبات لمفتاحك
    POST/linksإنشاء رابط مختصر (url، و slug اختياري، و domain و title و tags)
    GET/linksعرض الروابط، الأحدث أولًا، مع ترقيم صفحات بالمؤشر (cursor)
    GET/links/{id}جلب رابط واحد
    DELETE/links/{id}حذف رابط
    POST/secretsإنشاء رابط سري (ciphertext و enc_version و ttl_seconds و burn_after_read، و passphrase_hash في خطة Pro)
    GET/secretsعرض البيانات الوصفية للأسرار (دون المحتوى أبدًا)
    DELETE/secrets/{id}إبطال سر وإتلاف محتواه
    POST/public/linksإنشاء رابط مجهول المصدر باستخدام client_id، بلا مفتاح
    POST/public/secretsإنشاء سر مجهول المصدر يُحذف بعد القراءة، بلا مفتاح

    تعيد القوائم { data, next_cursor }. لمتابعة القائمة أعد إرسال next_cursor في cursor. قيمة limit من 1 إلى 100.

    3. أمثلة

    إنشاء رابط باستخدام curl

    curl -X POST "https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/links" \
      -H "Authorization: Bearer $LINKPILOT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"url":"https://example.com/launch","slug":"launch","tags":["campaign"]}'

    إنشاء سر من JavaScript

    const b64u = (b) => btoa(String.fromCharCode(...new Uint8Array(b)))
      .replace(/+/g, "-").replace(///g, "_").replace(/=+$/, "");
    
    // 1. Encrypt locally. This key is generated here and never sent anywhere.
    const key = crypto.getRandomValues(new Uint8Array(32));
    const iv = crypto.getRandomValues(new Uint8Array(12));
    const k = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]);
    const ct = await crypto.subtle.encrypt(
      { name: "AES-GCM", iv, tagLength: 128 },
      k,
      new TextEncoder().encode("staging db password"),
    );
    const ciphertext = `v1.${b64u(iv)}.${b64u(ct)}`;
    
    // 2. Store the blob. LinkPilot cannot read it.
    const res = await fetch("https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/secrets", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.LINKPILOT_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ ciphertext, enc_version: 1, ttl_seconds: 3600 }),
    });
    if (!res.ok) throw new Error((await res.json()).error.code);
    const { secret_url } = await res.json();
    
    // 3. Attach the key. Without this the link can never be opened, by anyone.
    const shareUrl = `${secret_url}#k=${b64u(key)}`;

    عرض الروابط من Python

    import os, requests
    
    r = requests.get(
        "https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/links",
        params={"limit": 20},
        headers={"Authorization": f"Bearer {os.environ['LINKPILOT_API_KEY']}"},
    )
    r.raise_for_status()
    for link in r.json()["data"]:
        print(link["short_url"], "->", link["url"])
    print("remaining this hour:", r.headers["X-RateLimit-Remaining"])

    إنشاء رابط مجهول المصدر بلا مفتاح

    curl -X POST "https://khiydxamyihofmtmgvjz.supabase.co/functions/v1/api-v1/public/links" \
      -H "Content-Type: application/json" \
      -d '{"url":"https://example.com","client_id":"my-cli-0123456789abcdef"}'

    ننشر العقد الرسمي هنا، لا في مستودع كود: مستند OpenAPI 3.1 و مجموعة Postman و المرجع المكتوب. وجّه مولّد الكود لديك مباشرة إلى عنوان OpenAPI.

    4. كيف تُخزَّن الأسرار

    نريد أن نكون دقيقين هنا، لأن على عميل API عملًا حقيقيًا: الواجهة لا تقبل payload بنص غير مشفر إطلاقًا.

    • أنت تشفّر، ونحن نخزن كتلة بيانات. أرسل ciphertext (AES-GCM-256، v1.<iv>.<ct>) مع enc_version: 1. إرسال payload يُرفض، ولا يُقبل بصمت.
    • عليك أن تضيف المفتاح بنفسك. لا يحتوي secret_url الذي نعيده على أي مفتاح، ولا يمكن أن يحتويه، لأننا لم نرَ المفتاح قط. أضف #k=<base64url key>. لا ترسل المتصفحات أبدًا الجزء الذي يلي علامة #، فيفك المستلم التشفير على جهازه.
    • لا يوجد استرجاع. إذا فقدت المفتاح ضاع السر، عليك وعلينا. هكذا يعمل الضمان.
    • يُتلف عند الحذف بعد القراءة أو انتهاء الصلاحية أو الإبطال. نكتب فوق النص المشفر المخزن على الخادم.
    • لا تعيده الواجهة أبدًا. لا يوجد مسار يعيد المحتوى أو النص المشفر. القارئ الوحيد هو صفحة الإظهار لدى المستلم، وهي تسجل المشاهدة.
    • عبارات المرور (في خطة Pro وما فوقها) عامل ثانٍ حقيقي: تُقوّى باستخدام PBKDF2-SHA256 وتُدمج في المفتاح باستخدام HKDF، فلا الرابط وحده ولا عبارة المرور وحدها تكفي لفك التشفير. أرسل passphrase_hash فقط، وهو قيمة تجزئة SHA-256 بالصيغة الست عشرية لعبارة المرور بعد توحيدها بصيغة NFKC. لا ترسل عبارة المرور الأصلية أبدًا، فهي نصف المفتاح. اشتق المفتاح من صيغة NFKC نفسها، حتى تفتح عبارة المرور السر إذا كُتبت على لوحة مفاتيح أخرى.
    • ما لا يغطيه. من يملك الرابط كاملًا يملك المفتاح، لذلك يبقى قِصر مدة الصلاحية والحذف بعد القراءة مهمين. تُشفَّر المرفقات بالطريقة نفسها، بمفتاح مشتق من الرابط نفسه.

    صيغة البيانات المتبادلة موصوفة في مرجع API، وتنفذ @uselinkpilot/sdk العملية كلها في استدعاء واحد إن لم ترغب في كتابتها بنفسك. والنموذج نفسه موصوف في صفحة بنية الأمان.

    5. حدود الخطط وحدود معدل الطلبات

    الحدFreeProAgency
    الروابط50غير محدودغير محدود
    الأسرار النشطة5100100
    أسرار بعبارة مرورلانعمنعم
    نطاقات مخصصة للروابطالنطاقات الموثقة الحاليةحتى 5غير محدود
    الطلبات لكل مفتاح في الساعة601,0005,000

    تطبق الواجهة قواعد الخطة نفسها المطبقة في لوحة التحكم وتقرؤها من المصدر نفسه، فيسري هنا أيضًا تجميع حدود الوكالة. يعيد GET /me الأرقام الحالية لمساحة عملك. وتحمل كل استجابة مصادَق عليها الترويسات X-RateLimit-Limit و X-RateLimit-Remaining و X-RateLimit-Reset.

    مقارنة الخطط

    6. مسارات عامة بلا مفتاح

    يوجد POST /public/links و POST /public/secrets للعملاء الذين لا يستطيعون عرض اختبار تحقق في المتصفح: أدوات CLI وخوادم MCP والمشغّل. يأخذ كلاهما client_id مُبهمًا (من 16 إلى 64 حرفًا، يُولَّد مرة واحدة لكل تثبيت)، وينشئ سجلات في المجموعة المجهولة المصدر نفسها التي تستخدمها أدوات الويب المجانية.

    • 20 عملية إنشاء لكل عميل في اليوم و60 لكل شبكة في الساعة، إضافة إلى حدود هذه المجموعة نفسها لكل شبكة.
    • الفحص نفسه بمصادر التهديدات، والاستعلام نفسه عن التهديدات في عناوين URL لدى Google، وإعادة الفحص المجدولة نفسها كما في كل طرق الإنشاء الأخرى.
    • لا نطاق مخصص ولا نهاية مخصصة ولا عبارة مرور. الأسرار العامة تُحذف نهائيًا دائمًا بعد قراءة واحدة، وتنتهي صلاحيتها خلال 24 ساعة.
    • تتضمن الاستجابة claim_token حتى يتمكن مستخدم سجّل الدخول لاحقًا من ضمّ السجل إلى مساحة عمل. تعامل معه كما تتعامل مع بيانات الدخول.

    7. الأخطاء

    كل خطأ يأتي بالشكل { "error": { "code", "message", "upgrade_url"? } }. تذكر الرسائل اسم الحقل، ولا تذكر بياناتك أبدًا. الموارد الموجودة في مساحات عمل أخرى تعيد 404، لا 403.

    الرمزHTTPمتى
    unauthorized401مفتاح مفقود أو مشوه أو غير معروف أو مُبطل أو منتهي الصلاحية
    disabled503الواجهة غير مفعّلة لهذا النشر بعد
    invalid_request400فشل التحقق من البيانات، أو وجهة محظورة، أو نهاية رابط مستخدمة، أو نطاق غير معروف
    not_found404المسار غير موجود، أو المورد ليس في مساحة عملك
    plan_limit402بلوغ حصة الروابط أو الأسرار النشطة (مع upgrade_url)
    pro_required402عبارة مرور في خطة لا تدعمها (مع upgrade_url)
    rate_limited429نفاد حصة المفتاح في الساعة أو الحصة العامة (مع Retry-After)

    أسئلة يطرحها المطورون

    أي الخطط تشمل الواجهة؟
    تُنشأ مفاتيح API من لوحة التحكم في /app/api-keys. ويستخدم كل مفتاح حدود خطة مساحة العمل التي ينتمي إليها: خطة Free تتيح 50 رابطًا و5 أسرار نشطة و60 طلبًا في الساعة، وخطة Pro تتيح روابط غير محدودة و100 سر نشط وأسرارًا محمية بعبارة مرور و1,000 طلب في الساعة، وتحصل خطط Agency على 5,000 طلب في الساعة.
    هل محتوى الأسرار مشفر من طرف إلى طرف؟
    نعم، والواجهة لا تقبل النص غير المشفر أصلًا. تشفّر أنت باستخدام AES-GCM-256 وترسل النص المشفر، ويخزن LinkPilot كتلة بيانات لا يملك مفتاحها ولا يستطيع فك تشفيرها. ولأننا لا نرى مفتاحك أبدًا، لا يحتوي secret_url الذي نعيده على أي مفتاح: تضيفه أنت بنفسك في صورة جزء #k= في آخر الرابط، ولا ترسل المتصفحات هذا الجزء أبدًا. إذا فقدت المفتاح فلن يستطيع أحد استرجاع السر، ولا نحن. تُشفَّر المرفقات بالطريقة نفسها، بمفتاح مشتق من الرابط نفسه.
    هل أستطيع إنشاء روابط بلا مفتاح API؟
    نعم. يأخذ POST /public/links و POST /public/secrets معرّف client_id مُبهمًا بدل المفتاح، وينشئان سجلات في المجموعة المجهولة المصدر نفسها التي تستخدمها أدوات الويب المجانية: 20 عملية إنشاء لكل عميل في اليوم، و60 لكل شبكة في الساعة، بلا نطاق مخصص ولا عبارة مرور، وتنتهي صلاحية الأسرار خلال 24 ساعة.
    ماذا يحدث عندما أبلغ حدًا؟
    تعيد حدود الخطة HTTP 402 مع الرمز plan_limit أو pro_required ومعه upgrade_url. وتعيد حدود معدل الطلبات 429 مع الترويسة Retry-After. وتحمل كل استجابة مصادَق عليها X-RateLimit-Limit و X-RateLimit-Remaining و X-RateLimit-Reset، حتى يبطئ العميل طلباته قبل أن يحدث ذلك.
    هل الواجهة مستقرة؟
    لن تتغير مسارات v1 بطريقة تكسر التوافق، وأي تغيير يكسر التوافق يصدر في إصدار جديد. خلال فترة الوصول المبكر نفعّل نقاط النهاية مساحة عمل تلو الأخرى، والاستجابة 503 مع الرمز disabled تعني أن الواجهة لم تُفعَّل لمساحة عملك بعد.

    هل أنت جاهز للبدء؟

    أنشئ مفتاحًا في مساحة عملك، أو ابدأ بخطة Free.