API للمطوّرين · الإصدار 1

أضف روابط المشاركة إلى تطبيقك

أنشئ روابط التطبيقات الذكية وروابط المحتوى — الرابط خلف زر «شارك» في تطبيقك — من الكود مباشرة. رابط المحتوى يفتح الشاشة الصحيحة في تطبيقك إن كان مثبتاً، والمتجر الصحيح إن لم يكن، وصفحتك على الويب في الكمبيوتر.

العنوان الأساسيhttps://donelinks.com/api/v1

نظرة عامة

كل الطلبات والإجابات JSON (UTF-8). أرسل مفتاحك في ترويسة Authorization.

رابط محتوى لكل منتج أو منشور أو دعوة

تطبيقك يطلب رابطاً عندما يضغط أحد «شارك»، والرابط يفتح نفس الشيء لمن يستلمه.

المتجر الصحيح أو الشاشة الصحيحة تلقائياً

iPhone وAndroid وHuawei والكمبيوتر، كلٌّ إلى وجهته، مع رابط تطبيقك أو صفحتك على الويب.

مفاتيح آمنة داخل التطبيقات

مفاتيح التطبيق تنشئ وتفتح روابط المحتوى فقط لروابط التطبيق التي تختارها. مفتاح السيرفر يبقى على سيرفرك.

محسوب ومحدود وواضح

كل إجابة تقول كم طلباً بقي هذا الشهر، والأخطاء تقول بالضبط ما يجب تصحيحه.

البداية السريعة

  1. 1
    أنشئ مفتاحاً

    الإعدادات ← API للمطوّرين: مفتاح سيرفر لسيرفرك، ومفتاح تطبيق لتطبيق الجوال.

  2. 2
    أنشئ رابط التطبيق مرة واحدة

    بروابط المتاجر ورابط تطبيقك (مثل noor://). تحته تعيش روابط المحتوى.

  3. 3
    أنشئ روابط المحتوى من التطبيق

    كل ضغطة «شارك» تطلب رابط محتوى بمسار الشاشة، ثم شارك الرابط الذي يعود.

  4. 4
    افتحها داخل التطبيق

    عندما يُفتح التطبيق من رابط، أرسله إلى ‎/resolve وافتح المسار الذي يعود.

curl https://donelinks.com/api/v1/me \
  -H "Authorization: Bearer dl_your_server_key"

المفاتيح والصلاحيات

أنشئ المفاتيح من الإعدادات ← API للمطوّرين. المفتاح يظهر مرة واحدة عند إنشائه، ونحفظ نسخة مشفّرة منه فقط. ألغِ أي مفتاح في أي وقت فيتوقف فوراً.

مفتاح سيرفر dl_…

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

مفتاح تطبيق dl_app_…

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

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

links:read
عرض روابط تطبيقاتك وقراءتها ورموز QR.
links:write
إنشاء روابط التطبيقات وتعديلها وحذفها (تشمل links:read).
content:write
إنشاء روابط المحتوى وعرضها وتعديلها وحذفها وقراءتها.
stats:read
إحصائيات الزيارات (Stats API — في الباقات التي تشمله).

الحدود

لكل حساب عدد طلبات API في الشهر (كل مفاتيحه معاً) وحد في الدقيقة، حسب باقته. الطلب الجماعي يُحسب طلباً لكل عنصر. الطلبات المرفوضة لمفتاح خاطئ أو صلاحية أو باقة لا تُحسب.

الباقةطلبات في الشهرطلبات في الدقيقة
احترافي10,00060
فريق100,000300
فريق بلس250,000600
مؤسساتبلا حد1,200

كل إجابة فيها هذه الترويسات:

X-RateLimit-Limit
طلبات الشهر في باقتك، أو "unlimited".
X-RateLimit-Remaining
الطلبات المتبقية هذا الشهر.
X-RateLimit-Reset
متى يبدأ الشهر من جديد (ثوانٍ Unix).
X-Request-Id
اذكره عند التواصل مع الدعم.

‏429 rate_limited: طلبات كثيرة في دقيقة — انتظر ثواني Retry-After. ‏429 quota_exceeded: انتهت طلبات الشهر — تبدأ من جديد أول الشهر، أو رقِّ باقتك.

الأخطاء

الأخطاء JSON فيها رمز ثابت ورسالة مفهومة، والحقل الذي يجب تصحيحه عند الحاجة:

{
  "error": {
    "code": "scope_required",
    "message": "This key cannot do that. It needs the \"links:write\" permission.",
    "scope": "links:write"
  },
  "requestId": "req_9QbX2kL0aV3m"
}
الرمزالحالةالمعنى
missing_key / invalid_key401لا يوجد مفتاح، أو مفتاح خاطئ أو ملغى.
plan_restricted403باقتك لا تشمل هذا (error.feature يقول ما هو).
scope_required403المفتاح لا يملك الصلاحية (error.scope).
link_not_allowed403مفتاح تطبيق استُعمل لرابط تطبيق لم يُنشأ له.
unknown_field / invalid_field / invalid_fields400حقل غير معروف أو غير صالح (error.field أو error.fields).
nothing_to_open400رابط المحتوى يحتاج path أو deepLink أو webUrl أو params.
link_not_found / content_not_found404غير موجود في هذا الحساب.
slug_taken409هذا الاسم مستخدم.
plan_limit_exceeded402وصلت لعدد الروابط في باقتك.
idempotency_mismatch422Idempotency-Key استُعمل مع طلب مختلف.
content_expired410رابط المحتوى تجاوز expiresAt.
rate_limited / quota_exceeded429حد الدقيقة أو طلبات الشهر.

إعادة المحاولة والصفحات

إعادة المحاولة بأمان (Idempotency-Key)

أرسل ترويسة Idempotency-Key (حتى 100 حرف أو رقم أو _-:.) عند إنشاء الروابط أو روابط المحتوى. إذا انقطع الاتصال وأعدت الطلب بنفس المفتاح خلال 24 ساعة، تعود لك النتيجة الأولى بدل رابط ثانٍ (مع ترويسة Idempotent-Replayed: true). الأخطاء لا تُحفظ، فالطلب المصحَّح يمكن إعادته.

صفحات النتائج

القوائم تعيد { data, hasMore, nextCursor }. اطلب الصفحة التالية بـ ‎?cursor=<nextCursor>، والعدد limit من 1 إلى 100 (افتراضياً 20).

روابط التطبيقات هي روابط DoneLinks التي تعرفها من اللوحة: رابط واحد يرسل كل زائر للمتجر الصحيح. الـ API ينشئ روابط التطبيقات ويديرها (الصفحات مثل روابطي والمنيو تبقى في اللوحة). كل قواعد الباقة في اللوحة تنطبق: عدد الروابط والأسماء المخصّصة والنطاقات والميزات.

الطريقةالمسارالصلاحيةالوظيفة
GET/meanyالمفتاح وحسابه واستعمال هذا الشهر
GET/linkslinks:readقائمة روابط التطبيقات (بحث q= وصفحات cursor)
POST/linkslinks:writeإنشاء رابط تطبيق
GET/links/{slug}links:readرابط تطبيق واحد
PATCH/links/{slug}links:writeتعديل رابط تطبيق (slug يغيّر اسمه)
DELETE/links/{slug}links:writeحذفه مع إحصائياته وروابط محتواه
GET/links/{slug}/qrlinks:readرمز QR (svg أو png)
curl -X POST https://donelinks.com/api/v1/links \
  -H "Authorization: Bearer dl_your_server_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: noor-shop-app" \
  -d '{
    "slug": "noor-shop",
    "title": "Noor Shop",
    "destinations": {
      "ios": "https://apps.apple.com/app/id1234567890",
      "android": "https://play.google.com/store/apps/details?id=com.noor.shop"
    },
    "defaultUrl": "https://noor.shop",
    "appSchemes": { "ios": "noor://", "android": "noor://" }
  }'

حقول الرابط

slug
اسم مخصّص (للباقات التي تشمله). عشوائي إن تركته.
title
اسمك الخاص للرابط.
destinations
{ ios, ipad, android, huawei, windows, mac, web, fallback } — روابط المتاجر والمواقع.
defaultUrl
وجهة كل زائر آخر.
appSchemes
{ ios, android } مثل "noor://" — منها تُبنى روابط فتح التطبيق لروابط المحتوى.
domain
نطاق خاص مؤكد في الحساب.
options
{ forwardParams, deferredDeepLink, desktopMode: auto | page | redirect }
campaigns
[{ id, name }] — نسخ متتبَّعة مثل ‎/noor-shop/instagram.
preview
{ title, description } يظهر عند مشاركة الرابط.
qr
تصميم رمز QR (النقش والألوان والإطار والشعار) كما في اللوحة.

في PATCH أرسل ما يتغير فقط، وnull يمسح الحقل. الحقول غير المعروفة تُرفض حتى لا يمر خطأ إملائي دون أن تلاحظه.

مثال الإجابة

{
  "id": "6720f1c2a9e4b1d3c5e7f901",
  "slug": "noor-shop",
  "url": "https://donelinks.com/noor-shop",
  "title": "Noor Shop",
  "domain": null,
  "destinations": {
    "ios": "https://apps.apple.com/app/id1234567890",
    "android": "https://play.google.com/store/apps/details?id=com.noor.shop"
  },
  "defaultUrl": "https://noor.shop",
  "appSchemes": { "ios": "noor://", "android": "noor://" },
  "options": { "forwardParams": false, "deferredDeepLink": false, "desktopMode": "auto" },
  "campaigns": [],
  "preview": null,
  "qr": {},
  "stats": { "clicks": 0, "qrScans": 0, "storeOpens": 0, "lastClickAt": null },
  "createdAt": "2026-10-19T09:30:00.000Z",
  "updatedAt": "2026-10-19T09:30:00.000Z"
}

رموز QR

GET /links/{slug}/qr يعيد رمز QR للرابط بتصميمه. format=svg (افتراضي) أو png، وsize من 128 إلى 2048 (افتراضياً 512)، وcampaign=<id> لرمز حملة. الرمز يفتح الرابط مع ‎?qr=1 حتى يُحسب المسح منفصلاً.

روابط المحتوى

رابط المحتوى يعيش تحت رابط التطبيق: ‎https://donelinks.com/noor-shop/Xk7pQ2a، أو على نطاقك go.noor.shop/noor-shop/Xk7pQ2a. الرمز 7 حروف وأرقام، وحالة الحروف مهمة.

الطريقةالمسارالصلاحيةالوظيفة
POST/links/{slug}/contentcontent:write · app keysإنشاء رابط محتوى
POST/links/{slug}/content/batchcontent:writeإنشاء حتى 100
GET/links/{slug}/contentlinks:read | content:writeقائمة روابط المحتوى
GET/links/{slug}/content/{code}links:read | content:writeرابط محتوى واحد مع أرقامه
PATCH/links/{slug}/content/{code}content:writeتعديله
DELETE/links/{slug}/content/{code}content:writeحذفه
curl -X POST https://donelinks.com/api/v1/links/noor-shop/content \
  -H "Authorization: Bearer dl_app_your_app_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: share-product-123" \
  -d '{
    "path": "product/123",
    "params": { "ref": "user-42" },
    "webUrl": "https://noor.shop/p/123",
    "preview": {
      "title": "Red dress",
      "description": "Only 20 JD this week",
      "imageUrl": "https://cdn.noor.shop/p/123.jpg"
    }
  }'

حقول رابط المحتوى (واحد على الأقل من path وdeepLink وwebUrl وparams)

path
الشاشة في تطبيقك، مثل "product/123". تُضاف إلى appSchemes لرابط التطبيق ← noor://product/123.
deepLink
أو رابط تطبيق صريح: "noor://p/123" أو { ios, android }.
params
حتى 20 قيمة نصية، تُضاف لروابط فتح التطبيق وتعود من ‎/resolve.
webUrl
نفس المحتوى على الويب: للكمبيوتر وحيث لا يمكن فتح التطبيق.
preview
{ title, description, imageUrl } — ما يظهر في واتساب وفيسبوك وX وغيرها.
campaign
إحدى حملات رابط التطبيق، لتُحسب الزيارات لها.
expiresAt
تاريخ ISO؛ بعده يرد الرابط 410 (للعروض والدعوات).

ماذا يفعل رابط المحتوى

Android
يفتح تطبيقك على المحتوى إن كان مثبتاً (intent في Chrome)، وإلا Google Play. ومع Deferred deep linking في باقتك، يمرّر Google Play الرابط للتطبيق بعد تثبيته.
iPhone وiPad
مع Universal Links على نطاقك يفتح iOS تطبيقك مباشرة، وإلا App Store.
الكمبيوتر
رابط webUrl للمحتوى؛ وبدونه ما يعطيه رابط التطبيق للكمبيوتر (موقعه أو صفحة التطبيق مع QR لهذا المحتوى).
تطبيقات المحادثة
واتساب وتيليغرام وفيسبوك وX ولينكدإن… تعرض معاينة المحتوى نفسه.

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

مثال الإجابة

{
  "code": "Xk7pQ2a",
  "url": "https://donelinks.com/noor-shop/Xk7pQ2a",
  "link": "noor-shop",
  "path": "product/123",
  "deepLink": { "ios": "noor://product/123?ref=user-42", "android": "noor://product/123?ref=user-42" },
  "params": { "ref": "user-42" },
  "webUrl": "https://noor.shop/p/123",
  "preview": { "title": "Red dress", "description": "Only 20 JD this week", "imageUrl": "https://cdn.noor.shop/p/123.jpg" },
  "campaign": null,
  "expiresAt": null,
  "stats": { "clicks": 0, "appOpens": 0, "lastClickAt": null },
  "createdAt": "2026-10-19T09:31:00.000Z",
  "updatedAt": "2026-10-19T09:31:00.000Z"
}

POST /links/{slug}/content/batch ينشئ حتى 100 دفعة واحدة. كلها أو لا شيء: إذا كان عنصر غير صالح لا يُنشأ شيء، وerror.index يقول أي عنصر.

curl -X POST https://donelinks.com/api/v1/links/noor-shop/content/batch \
  -H "Authorization: Bearer dl_your_server_key" \
  -H "Content-Type: application/json" \
  -d '{ "items": [
    { "path": "product/1", "webUrl": "https://noor.shop/p/1" },
    { "path": "product/2", "webUrl": "https://noor.shop/p/2" },
    { "path": "product/3", "campaign": "instagram" }
  ] }'

القراءة داخل التطبيق

عندما يفتح رابط DoneLinks تطبيقك — عبر Universal Links / App Links على نطاقك، أو بعد التثبيت من Google Play مباشرة — أرسل الرابط إلى ‎/resolve وافتح ما يعود. ويُحسب الفتح داخل التطبيق.

الطريقةالمسارالصلاحيةالوظيفة
GET/resolve?url=…content:resolve · app keysماذا يجب أن يفتح الرابط داخل التطبيق
curl -G https://donelinks.com/api/v1/resolve \
  -H "Authorization: Bearer dl_app_your_app_key" \
  --data-urlencode "url=https://go.noor.shop/noor-shop/Xk7pQ2a"

ملاحظة صريحة: على iPhone لا يمكن فتح المحتوى مباشرة بعد التثبيت الأول بدون SDK داخل التطبيق (Apple لا تمرّر الرابط عبر App Store). DoneLinks لا يستعمل تقنيات التخمين (fingerprinting). يفتح التطبيق عادياً، والروابط التي تُضغط بعدها تفتح المحتوى.

دليل زر المشاركة

  1. 1
    أنشئ رابط التطبيق (مرة واحدة)

    بروابط المتاجر ورابط التطبيق. إذا عندك نطاق خاص ضع الرابط عليه: Universal Links تحتاج نطاقك الخاص.

  2. 2
    في التطبيق: عند «شارك»

    اطلب رابط محتوى بمسار الشاشة ومعاينتها، ثم شارك الرابط.

  3. 3
    في التطبيق: عند الفتح من رابط

    أرسل الرابط إلى ‎/resolve وافتح المسار العائد.

  4. 4
    Android بعد التثبيت

    اقرأ Install Referrer مرة واحدة وأرسله إلى ‎/resolve (Deferred deep linking).

Universal Links (iOS) وApp Links (Android)

حتى تفتح الروابط تطبيقك مباشرة يجب أن يثق التطبيق بنطاقك. أضف نطاقك من الإعدادات ← النطاقات الخاصة، ثم ارفع هذين الملفين في «الفتح في التطبيق». DoneLinks يقدّمهما على نطاقك.

{
  "applinks": {
    "details": [
      {
        "appIDs": ["TEAMID.com.noor.shop"],
        "components": [{ "/": "/noor-shop/*" }]
      }
    ]
  }
}
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.noor.shop",
    "sha256_cert_fingerprints": ["AB:CD:EF:…"]
  }
}]
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="go.noor.shop" android:pathPrefix="/noor-shop/" />
</intent-filter>

الإحصائيات

GET /stats هو Stats API: الزيارات يومياً وحسب الجهاز والدولة والموقع المحيل وUTM لكل رابط (period=yesterday | 30d | 400d، وlink=<slug>، وformat=csv). يحتاج صلاحية stats:read وباقة تشمل Stats API. المفاتيح التي أُنشئت له سابقاً تبقى تعمل.

الطريقةالمسارالصلاحيةالوظيفة
GET/statsstats:readإحصائيات الزيارات (Stats API)

الانتقال من Firebase Dynamic Links

Firebase Dynamic Links توقفت في آب 2025. هكذا تقابل أجزاؤها DoneLinks:

نطاق Dynamic Link ‏(xyz.page.link)نطاقك (go.brand.com) أو ‎https://donelinks.com
بارامترات ibi وisi وapn وafl وiflرابط التطبيق: destinations وappSchemes
link= (رابط فتح التطبيق)رابط المحتوى: path أو deepLink، وwebUrl
وسوم المشاركة st وsd وsiرابط المحتوى: preview { title, description, imageUrl }
REST API shortLinksPOST /links/{slug}/content
getDynamicLink / handleUniversalLinkGET /resolve
Deferred deep linksAndroid: نعم (Install Referrer). iOS: لا (انظر الملاحظة أعلاه).

OpenAPI والأدوات

الـ API كاملاً موصوف بـ OpenAPI 3.1: استورده في Postman أو Insomnia، أو أنشئ منه مكتبة، أو أعطه لمساعد ذكاء اصطناعي.

OpenAPI 3.1https://donelinks.com/api/v1/openapi.json

Postman: Import ← Link ← الصق عنوان OpenAPI.