مرجع API

REST API
ابنِ على روابطك.

صادِق باستخدام رمز API، واعرض الروابط وأنشئها، واقرأ الزيارات، واشترك في Webhooks.

عنوان URL الأساسي https://letl.ink/api/v1 HTTPS فقط

الخطط Growth Ultimate
في هذه الصفحة

البدء

تتوفر REST API في Growth وUltimate. تُرسَل الطلبات إلى https://letl.ink/api/v1 عبر HTTPS. مساحة العمل على Free أو Solo تتلقى 403 plan_required من /api/v1؛ أما نقطة نهاية MCP فمقيّدة بشكل منفصل على Ultimate.

  1. افتح التكاملات ← REST API (لمالكي مساحة العمل ومشرفيها فقط).
  2. أنشئ رمزًا. لا تنتهي صلاحيته.
  3. احفظه كما تحفظ كلمة مرور. رمز واحد يخدم REST API وخادم MCP وكل منصة أتمتة متصلة بمساحة العمل هذه، لذا فإن إعادة إنشائه تُبطلها جميعًا دفعة واحدة.

يمكن للأعضاء نسخ رمز موجود إذا تم إنشاؤه؛ ولا يمكن تبديله إلا للمالكين والمشرفين.

المصادقة

أرسل الرمز كـ X-API-KEY أو كـ Authorization: Bearer. كلاهما مقبول على /api/v1 وعلى /mcp. الطلب الذي لا يحتوي على أي رمز يُرجع 401 unauthenticated.

GET من أنا؟
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/auth/me

الترويسة المكافئة: Authorization: Bearer YOUR_TOKEN

الاصطلاحات

تنطبق هذه على جميع نقاط النهاية أدناه.

غلاف الاستجابة

كل استجابة ناجحة كائن JSON يحتوي على مفتاح data، ومفتاح meta عندما يكون هناك ما يُقال عن النتيجة — ترقيم الصفحات، والفترة الزمنية المحددة، وما إذا كانت البيانات الجغرافية مضمّنة. وكل إخفاق كائن يحتوي على مفتاح error يحمل code ثابتًا وmessage مقروءًا، وأحيانًا details. اعتمد في التفرّع على code، لا على نص الرسالة أبدًا.

الأشكال
// success
{ "data": { … }, "meta": { … } }

// failure
{ "error": { "code": "invalid_parameter",
             "message": "sort must be one of: created_at, clicks.",
             "details": { "parameter": "sort" } } }

ترقيم الصفحات

تقبل نقاط نهاية القوائم limit ‏(1–200، الافتراضي 50) وoffset. تُبلغ كتلة meta عن total وhas_more وnext_offset، لتتمكن من التنقل بين الصفحات دون حسابات: استمر في الاستدعاء بـ offset = meta.next_offset حتى يصبح has_more هو false.

التنقل بين كل الروابط
offset=0
while [ "$offset" != "null" ]; do
  page=$(curl -s -H "X-API-KEY: $TOKEN" \
    "https://letl.ink/api/v1/links?limit=200&offset=$offset")
  echo "$page" | jq -c '.data[]'
  offset=$(echo "$page" | jq -r '.meta.next_offset')
done

الترتيب والتصفية والبحث

تقبل GET /links المعلمات sort (created_at وclicks وshort_code وtitle وupdated_at) وdirection (asc/desc) وsearch (يطابق الرمز القصير والعنوان والوجهة) وtype وarchived وfavorite وdomain. تُرفض القيم غير المعروفة مع invalid_parameter وقائمة بالقيم المسموح بها، بدلًا من تجاهلها بصمت.

الفترات الزمنية

يستخدم start_date وend_date الصيغة YYYY-MM-DD ويشملان اليومين كليهما. تُقيَّد الفترة بحد الاحتفاظ في خطتك — فطلب سجل سنة كاملة من خطة احتفاظها 30 يومًا يُرجع الأيام الثلاثين المتاحة، ويخبرك meta.date_range بالفترة المستخدمة فعليًا.

حدود معدل الطلبات

600 طلب في الدقيقة لكل حساب، وفق نافذة منزلقة. تحمل كل استجابة X-RateLimit-Limit وX-RateLimit-Remaining وX-RateLimit-Reset (طابع زمني Unix). يؤدي تجاوز الحد إلى إرجاع 429 rate_limited مع ترويسة Retry-After بالثواني. انتظر حسب Retry-After بدلًا من إعادة المحاولة فورًا.

الترويسات في كل استجابة
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 586
X-RateLimit-Reset: 1789000816

الإصدارات

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

نقاط النهاية

الحساب

GET /me اختبار الاتصال

الهوية ومساحة العمل والخطة وكل الصلاحيات التي تحملها تلك الخطة. أبسط طريقة للتحقق من الرمز ومعرفة ما يُسمح للحساب بفعله قبل أن تحاول.

GET cURL
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/me
الاستجابة 200
{
  "data": {
    "user": { "id": 1, "email": "[email protected]", "name": "You" },
    "workspace": { "id": 12, "name": "My Workspace", "block_bots": true },
    "plan": {
      "id": "growth",
      "name": "Growth",
      "limits": {
        "links": 200,
        "monthly_clicks": 100000,
        "custom_domains": 3,
        "qr_codes": 30,
        "retention_days": 365
      },
      "features": {
        "api": true,
        "webhooks": true,
        "integrations": true,
        "ai_access": false,
        "geo_analytics": false,
        "smart_link_types": true
      }
    },
    "base_domain": "letl.ink"
  }
}
GET /usage

مقدار ما استُهلك من كل حصة في شهر الفوترة هذا. استخدمه لتنبيه العميل قبل أن يبلغ سقف النقرات المتتبَّعة — فبعده تستمر إعادة التوجيه، لكن يتوقف تسجيل النقرات.

الاستجابة 200
{
  "data": {
    "links": { "used": 42, "limit": 200, "remaining": 158, "percent_used": 21.0 },
    "clicks_this_month": { "used": 8140, "limit": 100000, "remaining": 91860, "percent_used": 8.1 },
    "custom_domains": { "used": 1, "limit": 3, "remaining": 2, "percent_used": 33.3 },
    "qr_codes": { "used": 4, "limit": 30, "remaining": 26, "percent_used": 13.3 }
  },
  "meta": { "plan": "growth", "period": "2026-09" }
}
GET /domains

النطاقات المخصصة في مساحة العمل وما إذا كان كل منها قد أكمل التحقق من DNS. لا يمكن استخدام سوى النطاقات التي تم التحقق منها كحقل domain عند إنشاء رابط.

GET /integrations

كل تكامل يقدمه المنتج، وما إذا كانت خطتك تتضمنه، وما إذا كانت مساحة العمل هذه قد ربطته، وحالة التسليم — آخر حالة وآخر خطأ وعدد الإخفاقات المتتالية. مفيد لمراقبة مجموعة من مساحات العمل.

الروابط

التحليلات

GET /analytics/summary

الأرقام الرئيسية لمساحة العمل بأكملها: النقرات منذ البداية وخلال الفترة، والزوار الفريدون، وعمليات مسح QR، ويوم الذروة، وتوزيع النقرات حسب ساعة اليوم ويوم الأسبوع. تقبل days (الافتراضي 30، ومقيّدة بفترة الاحتفاظ لديك).

الاستجابة 200 (مختصر)
{
  "data": {
    "window_days": 30,
    "clicks": {
      "total": 24592, "window": 8140, "last_7_days": 2103,
      "daily_average": 271,
      "peak_day": { "date": "Sep 02", "clicks": 612 }
    },
    "visitors": { "unique_total": 18204, "unique_window": 6021 },
    "qr": { "scans_total": 940, "scans_window": 310 },
    "timing": {
      "by_hour": [12, 4, 2, …],
      "by_weekday": [1420, 1610, 1585, 1490, 1310, 480, 245],
      "peak_hour": { "peakHour": 14, "peakValue": 812, "label": "14:00–14:59" },
      "peak_weekday": { "peakDay": 1, "peakValue": 1610, "label": "Tuesday" }
    },
    "links": { "active": 42, "limit": 200 }
  },
  "meta": { "plan": "growth", "geo_included": true, "retention_days": 365 }
}
GET /analytics/timeseries

أعداد النقرات اليومية، جاهزة للرسم البياني. مرّر link_id لحصرها في رابط واحد، وdays لتحديد الفترة. تُرجع الأيام التي بلا زيارات بقيمة صفر بدلًا من حذفها، فتبقى السلسلة متصلة دائمًا.

الاستجابة 200
{
  "data": [
    { "date": "Sep 04", "clicks": 22 },
    { "date": "Sep 05", "clicks": 11 }
  ],
  "meta": { "window_days": 7, "total": 33, "link_id": null }
}
GET /analytics/breakdown

النقرات مجمّعة حسب بُعد واحد، مع حصة كل صف من الإجمالي.

معلمات الاستعلام

  • dimension string

    channel وreferrer وdevice وbrowser وos وbrand وvariation أو country. تحتاج browser وos وbrand وvariation إلى link_id.

    مطلوب
  • link_id integer

    قصر النتائج على رابط واحد. احذفه لمساحة العمل بأكملها.

    اختياري
  • limit integer

    1–100. القيمة الافتراضية 10.

    اختياري
الاستجابة 200
{
  "data": [
    { "label": "Search", "value": 215, "share": 33.1 },
    { "label": "Social", "value": 201, "share": 30.9 },
    { "label": "Direct / none", "value": 142, "share": 21.8 }
  ],
  "meta": { "dimension": "channel", "link_id": 49, "total": 650 }
}
GET /events مقسّم إلى صفحات

موجز الزيارات الخام لجميع الروابط في مساحة العمل، الأحدث أولًا. هذا هو البديل الحديث لـ GET /visits: البيانات نفسها، والغلاف القياسي، ودعم limit وoffset.

الاستجابة 200
{
  "data": [
    {
      "id": 2691,
      "link_id": 49,
      "short_code": "spring",
      "occurred_at": "2026-09-10T22:45:33+00:00",
      "ip_address": "203.0.113.7",
      "referrer": "https://twitter.com/",
      "browser": "Chrome",
      "os": "iOS",
      "device_type": "mobile",
      "device_brand": "Apple",
      "country": "US",
      "variation": "control"
    }
  ],
  "meta": { "limit": 50, "returned": 50, "geo_included": true }
}

Webhooks

GET /hooks

نقاط نهاية Webhooks المسجلة في هذا الحساب.

POST /hooks

سجّل نقطة نهاية HTTPS لتلقي حمولة JSON عند كل نقرة مسجّلة. حتى 25 لكل حساب. تُعاد محاولة عمليات التسليم الفاشلة تلقائيًا.

نص JSON

  • target_url

    يجب أن يبدأ بـ https://.

    مطلوب
  • event

    القيمة الافتراضية link_visited، وهو الحدث الوحيد حاليًا.

    اختياري
POST cURL
curl -X POST https://letl.ink/api/v1/hooks \
  -H "X-API-KEY: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"target_url": "https://example.com/hooks/clicks"}'
DELETE /hooks/{id}

أزل نقطة نهاية Webhook. تبقى POST /hooks/subscribe وDELETE /hooks/unsubscribe/{id} متاحتين لتدفق REST Hook في Zapier.

قديم

GET /auth/me قديم

اختبار الاتصال الأصلي: يُرجع معرّف المستخدم وبريدك الإلكتروني ومعرّف مساحة العمل واسمها ككائن مسطّح. أما GET /me فيُرجع الهوية نفسها إضافةً إلى حدود خطتك وعلامات الميزات، وهو الخيار الأفضل للشيفرة الجديدة.

GET cURL
curl -H "X-API-KEY: YOUR_TOKEN" \
  https://letl.ink/api/v1/auth/me
الاستجابة 200
{
  "id": 1,
  "email": "[email protected]",
  "workspace_id": 12,
  "workspace_name": "My Workspace"
}
GET /visits قديم

أحدث 50 زيارة عبر مساحة العمل في صورة مصفوفة JSON مجردة — دون غلاف — باستخدام أسماء الحقول visit_id وvisit_time وlink_shortcode وvisitor_*. هذا ما تقرؤه خطوة «perform list» في REST Hook لدى Zapier، لذا فبنيتها مجمّدة. استخدم GET /events في أي عمل جديد.

POST /hooks/subscribe Zapier

اشتراك REST Hook. يأخذ target_url وevent اختياريًا (الافتراضي link_visited) ويُرجع الاشتراك المُنشأ مباشرةً، دون غلاف. وPOST /hooks هي العملية نفسها بالبنية القياسية.

DELETE /hooks/unsubscribe/{id} Zapier

إلغاء اشتراك REST Hook، ويُرجع {"success": true}. وDELETE /hooks/{id} هي المكافئ بالبنية القياسية.

الأخطاء

  • 400 invalid_request

    المتن ليس كائن JSON، أو أن حقلًا مطلوبًا مفقود.

  • 400 invalid_parameter

    معلمة استعلام مشوّهة أو خارج مجموعة القيم المسموح بها. يحدد details.parameter المعلمة المخالفة.

  • 401 unauthenticated

    لم يُرسَل أي رمز. أضف X-API-KEY أو Authorization: Bearer.

  • 401 invalid_token

    لا يطابق الرمز أي حساب. ربما تم تجديده.

  • 403 plan_required

    خطة الحساب لا تتضمن نقطة النهاية أو الميزة هذه. يشير details.upgrade_url إلى صفحة الفوترة.

  • 403 forbidden

    تمت المصادقة، لكن الإجراء غير مسموح — مثل عضو يحاول تنفيذ إجراء مخصص للمالك.

  • 404 not_found

    لا يوجد مورد كهذا في مساحة العمل هذه. يُبلَّغ عن المعرّفات من مساحة عمل أخرى بأنها غير موجودة بدلًا من أنها محظورة.

  • 409 conflict

    يتعارض الطلب مع الحالة الحالية — تم بلوغ حد Webhooks، أو لا يملك الحساب مساحة عمل بعد.

  • 422

    يُرجع من POST /links/bulk عندما تفشل كل صفوف الدفعة. افحص meta.errors.

  • 429 rate_limited

    أكثر من 600 طلب في الدقيقة الأخيرة. انتظر عدد الثواني المحدد في Retry-After.

نقطتا النهاية القديمتان GET /visits وGET /links/{id}/visits تُرجعان مصفوفة JSON مجردة بأسماء حقول خاصة بهما، وهما مجمّدتان من أجل تكاملات Zapier المبنية عليهما بالفعل. يجب أن تستخدم الشيفرة الجديدة GET /events وGET /links/{id}/events، اللتين تستخدمان الغلاف القياسي وتدعمان التقسيم إلى صفحات.

هل لا تزال لديك أسئلة؟

نحن هنا للمساعدة. تواصل معنا وسنرد عليك في أقرب وقت ممكن.