نظرة عامة
كل الطلبات والإجابات JSON (UTF-8). أرسل مفتاحك في ترويسة Authorization.
تطبيقك يطلب رابطاً عندما يضغط أحد «شارك»، والرابط يفتح نفس الشيء لمن يستلمه.
iPhone وAndroid وHuawei والكمبيوتر، كلٌّ إلى وجهته، مع رابط تطبيقك أو صفحتك على الويب.
مفاتيح التطبيق تنشئ وتفتح روابط المحتوى فقط لروابط التطبيق التي تختارها. مفتاح السيرفر يبقى على سيرفرك.
كل إجابة تقول كم طلباً بقي هذا الشهر، والأخطاء تقول بالضبط ما يجب تصحيحه.
البداية السريعة
- 1أنشئ مفتاحاً
الإعدادات ← API للمطوّرين: مفتاح سيرفر لسيرفرك، ومفتاح تطبيق لتطبيق الجوال.
- 2أنشئ رابط التطبيق مرة واحدة
بروابط المتاجر ورابط تطبيقك (مثل noor://). تحته تعيش روابط المحتوى.
- 3أنشئ روابط المحتوى من التطبيق
كل ضغطة «شارك» تطلب رابط محتوى بمسار الشاشة، ثم شارك الرابط الذي يعود.
- 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,000 | 60 |
| فريق | 100,000 | 300 |
| فريق بلس | 250,000 | 600 |
| مؤسسات | بلا حد | 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_key | 401 | لا يوجد مفتاح، أو مفتاح خاطئ أو ملغى. |
plan_restricted | 403 | باقتك لا تشمل هذا (error.feature يقول ما هو). |
scope_required | 403 | المفتاح لا يملك الصلاحية (error.scope). |
link_not_allowed | 403 | مفتاح تطبيق استُعمل لرابط تطبيق لم يُنشأ له. |
unknown_field / invalid_field / invalid_fields | 400 | حقل غير معروف أو غير صالح (error.field أو error.fields). |
nothing_to_open | 400 | رابط المحتوى يحتاج path أو deepLink أو webUrl أو params. |
link_not_found / content_not_found | 404 | غير موجود في هذا الحساب. |
slug_taken | 409 | هذا الاسم مستخدم. |
plan_limit_exceeded | 402 | وصلت لعدد الروابط في باقتك. |
idempotency_mismatch | 422 | Idempotency-Key استُعمل مع طلب مختلف. |
content_expired | 410 | رابط المحتوى تجاوز expiresAt. |
rate_limited / quota_exceeded | 429 | حد الدقيقة أو طلبات الشهر. |
إعادة المحاولة والصفحات
إعادة المحاولة بأمان (Idempotency-Key)
أرسل ترويسة Idempotency-Key (حتى 100 حرف أو رقم أو _-:.) عند إنشاء الروابط أو روابط المحتوى. إذا انقطع الاتصال وأعدت الطلب بنفس المفتاح خلال 24 ساعة، تعود لك النتيجة الأولى بدل رابط ثانٍ (مع ترويسة Idempotent-Replayed: true). الأخطاء لا تُحفظ، فالطلب المصحَّح يمكن إعادته.
صفحات النتائج
القوائم تعيد { data, hasMore, nextCursor }. اطلب الصفحة التالية بـ ?cursor=<nextCursor>، والعدد limit من 1 إلى 100 (افتراضياً 20).
الروابط
روابط التطبيقات هي روابط DoneLinks التي تعرفها من اللوحة: رابط واحد يرسل كل زائر للمتجر الصحيح. الـ API ينشئ روابط التطبيقات ويديرها (الصفحات مثل روابطي والمنيو تبقى في اللوحة). كل قواعد الباقة في اللوحة تنطبق: عدد الروابط والأسماء المخصّصة والنطاقات والميزات.
| الطريقة | المسار | الصلاحية | الوظيفة |
|---|---|---|---|
| GET | /me | any | المفتاح وحسابه واستعمال هذا الشهر |
| GET | /links | links:read | قائمة روابط التطبيقات (بحث q= وصفحات cursor) |
| POST | /links | links:write | إنشاء رابط تطبيق |
| GET | /links/{slug} | links:read | رابط تطبيق واحد |
| PATCH | /links/{slug} | links:write | تعديل رابط تطبيق (slug يغيّر اسمه) |
| DELETE | /links/{slug} | links:write | حذفه مع إحصائياته وروابط محتواه |
| GET | /links/{slug}/qr | links: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}/content | content:write · app keys | إنشاء رابط محتوى |
| POST | /links/{slug}/content/batch | content:write | إنشاء حتى 100 |
| GET | /links/{slug}/content | links: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أنشئ رابط التطبيق (مرة واحدة)
بروابط المتاجر ورابط التطبيق. إذا عندك نطاق خاص ضع الرابط عليه: Universal Links تحتاج نطاقك الخاص.
- 2في التطبيق: عند «شارك»
اطلب رابط محتوى بمسار الشاشة ومعاينتها، ثم شارك الرابط.
- 3في التطبيق: عند الفتح من رابط
أرسل الرابط إلى /resolve وافتح المسار العائد.
- 4Android بعد التثبيت
اقرأ 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 | /stats | stats: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 shortLinks | POST /links/{slug}/content |
| getDynamicLink / handleUniversalLink | GET /resolve |
| Deferred deep links | Android: نعم (Install Referrer). iOS: لا (انظر الملاحظة أعلاه). |
OpenAPI والأدوات
الـ API كاملاً موصوف بـ OpenAPI 3.1: استورده في Postman أو Insomnia، أو أنشئ منه مكتبة، أو أعطه لمساعد ذكاء اصطناعي.
https://donelinks.com/api/v1/openapi.jsonPostman: Import ← Link ← الصق عنوان OpenAPI.