واجهة نقرة البرمجية
أنشئ الروابط القصيرة وعدّلها واقرأ تحليلاتها من متجرك أو خادمك. كل الطلبات والردود بصيغة JSON، وكل طلب يحمل مفتاح API لمساحة العمل.
- العنوان الأساسي
https://api.nqra.link/api/v1- الصيغة
application/json- حد الطلبات
- 600 طلب كل 60 ثانية لكل مفتاح API. عند تجاوزها تصلك 429؛ انتظر المدة في Retry-After ثم أعد المحاولة.
هذه الصفحة دليل الاستخدام. أما المرجع فيعرض كل نقطة وحقل ورد بالتفصيل.
المصادقة
أرسل بيانات الاعتماد مع كل طلب في إحدى هاتين الترويستين:
| الترويسة | القيمة |
|---|---|
x-api-key | nq_live_… مفتاح API لمساحة عملك. |
Authorization | Bearer <token> رمز وصول OAuth 2.1 أو رمز جلسة. أرسله بدلاً من المفتاح لا معه. |
أنشئ المفاتيح من لوحة التحكم في «للمطوّرين» ثم «مفاتيح API». المفتاح يتبع مساحة عمل لا شخصاً، ولا يملك إلا الصلاحيات التي تمنحها له. الواجهة البرمجية جزء من الخطط المدفوعة.
تستخدم كل الأمثلة في هذه الصفحة هذه الدالة الصغيرة:
const API = "https://api.nqra.link/api/v1";
const KEY = process.env.NQRA_API_KEY; // nq_live_…, from Developers → API keys
async function nqra(method, path, payload) {
const res = await fetch(`${API}${path}`, {
method,
headers: { "content-type": "application/json", "x-api-key": KEY },
body: payload ? JSON.stringify(payload) : undefined,
});
if (!res.ok) throw new Error((await res.json()).error.code);
return res.status === 204 ? null : res.json();
}أو بـ curl:
curl -X POST "https://api.nqra.link/api/v1/links" \
-H "x-api-key: $NQRA_API_KEY" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/a-long-address"}'curl "https://api.nqra.link/api/v1/links" -H "authorization: Bearer $ACCESS_TOKEN"الأخطاء
عند الخطأ يرجع رمز حالة HTTP وجسم فيه كائن error: رمز ثابت code ورسالة message وأحياناً details. اعتمد على code فالرسائل قد تتغير.
{ "error": { "code": "SLUG_TAKEN", "message": "Slug already taken." } }| الحالة | الرمز | المعنى |
|---|---|---|
| 400 | AMBIGUOUS_CREDENTIALS | أُرسل نوعان من بيانات الاعتماد معاً، مثل جلسة ومفتاح API. أرسل نوعاً واحداً. |
| 400 | DOMAIN_APEX | النطاق الرئيسي لا يصلح نطاقاً مخصصاً؛ استخدم نطاقاً فرعياً مثل go.example.com. |
| 400 | DOMAIN_INVALID | اسم النطاق غير صالح. |
| 400 | DOMAIN_RESERVED | النطاق محجوز لنقرة. |
| 400 | MAX_CLICKS_BELOW_COUNT | قيمة maxClicks أقل من عدد النقرات المسجلة على الرابط. |
| 400 | NO_FIELDS | أُرسل تعديل بلا أي حقل للتغيير. |
| 400 | URL_REJECTED | عنوان الوجهة غير مسموح. يوضح details.reason السبب. |
| 400 | VALIDATION_FAILED | جسم الطلب أو معاملاته أو مساره غير صالح. يسرد details كل مشكلة. |
| 401 | API_KEY_INVALID | مفتاح API خاطئ أو منتهي أو مُلغى. |
| 401 | UNAUTHENTICATED | لم تُرسل بيانات اعتماد، أو انتهت صلاحيتها. |
| 403 | EMAIL_NOT_VERIFIED | لم يُؤكَّد البريد الإلكتروني للحساب بعد. |
| 403 | FORBIDDEN | المفتاح أو الرمز لا يملك الصلاحية التي يحتاجها هذا الطلب. |
| 403 | PLAN_LIMIT | خطة مساحة العمل لا تشمل هذه الميزة. يحدد details الميزة. |
| 404 | LINK_NOT_FOUND | الرابط غير موجود في مساحة العمل هذه. |
| 404 | NOT_FOUND | المورد غير موجود في مساحة العمل هذه. |
| 409 | ALREADY_MEMBER | الشخص عضو في مساحة العمل بالفعل. |
| 409 | DOMAIN_TAKEN | النطاق مستخدم ولا يمكن تسجيله مرة أخرى. |
| 409 | DOWNGRADE_BLOCKED | الاستخدام الحالي أكبر مما تسمح به الخطة الجديدة. يسرد details.over ما يجب تقليله. |
| 409 | NO_ACTIVE_ORG | لا توجد مساحة عمل نشطة في الجلسة. |
| 409 | SLUG_RESERVED | اسم الرابط من الأسماء التي تحتفظ بها نقرة لنفسها. |
| 409 | SLUG_TAKEN | اسم الرابط مستخدم. الروابط المحذوفة تبقى أسماؤها محجوزة. |
| 409 | TAG_EXISTS | يوجد وسم بهذا الاسم. |
| 409 | VERSION_MISMATCH | تغيّر السجل أثناء تنفيذ الطلب. اقرأه من جديد ثم أعد المحاولة. |
| 429 | QUOTA_EXCEEDED | استهلكت مساحة العمل حصتها من هذه الميزة. يحوي details الميزة والحد، وما تبقى إن عُرف. |
| 429 | RATE_LIMITED | طلبات كثيرة. انتظر عدد الثواني في ترويسة Retry-After. |
| 500 | INTERNAL | حدث خطأ لدينا. أعد المحاولة، وإن تكرر تواصل مع الدعم. |
| 502 | UPSTREAM_FAILED | تعطلت خدمة نعتمد عليها. أعد المحاولة. |
| 503 | ANALYTICS_UNAVAILABLE | التحليلات غير متاحة مؤقتاً. أعد المحاولة بعد قليل. |
| 503 | BILLING_UNAVAILABLE | الفوترة غير متاحة مؤقتاً. |
| 503 | DOMAINS_UNAVAILABLE | النطاقات المخصصة غير متاحة مؤقتاً. |
| 503 | SLUG_GENERATION_FAILED | تعذّر إيجاد اسم عشوائي متاح. أعد المحاولة. |
حد الطلبات
600 طلب كل 60 ثانية لكل مفتاح API. عند تجاوزها تصلك 429؛ انتظر المدة في Retry-After ثم أعد المحاولة.
HTTP/1.1 429 Too Many Requests
retry-after: 60
{ "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded." } }يحمل الرد 429 الرمز RATE_LIMITED وترويسة Retry-After بعدد الثواني التي عليك انتظارها. أما نفاد الحصة الشهرية فيرجع QUOTA_EXCEEDED، ولا ينفع معه انتظار ثوانٍ.
POST/linksإنشاء رابط
يُنشئ رابطاً قصيراً. إن لم ترسل slug نولّد اسماً عشوائياً.
| الحقل | النوع | الوصف |
|---|---|---|
urlمطلوب | string | الوجهة. يجب أن تبدأ بـ http:// أو https://. |
slug | string | اسم الرابط: من 3 إلى 64 حرفاً من A-Z وa-z و0-9 و- و_. |
title | string | عنوان لتمييز الرابط عندك، حتى 200 حرف. أرسل null لمسحه عند التعديل. |
tags | string[] | قائمة وسوم تُحفظ بأحرف صغيرة. |
expiresAt | number | وقت الانتهاء بالمللي ثانية (Unix). يجب أن يكون في المستقبل. |
maxClicks | number | عدد صحيح موجب. بعد بلوغه يتوقف التحويل. |
await nqra("POST", "/links", {
url: "https://rawafid.manhali.com/courses/python-basics",
slug: "python-101",
tags: ["courses"],
maxClicks: 500,
});{
"slug": "python-101",
"shortUrl": "https://nqra.link/python-101",
"url": "https://rawafid.manhali.com/courses/python-basics",
"title": null,
"tags": [{ "id": "tag_…", "name": "courses", "color": "#0d6b88" }],
"status": "active",
"expiresAt": null,
"maxClicks": 500,
"clickCount": 0,
"isActive": true,
"safetyStatus": "pending",
"createdAt": 1790000000000,
"updatedAt": 1790000000000
}يرجع 409 SLUG_TAKEN إن كان الاسم مستخدماً (الروابط المحذوفة تبقى أسماؤها محجوزة)، و409 SLUG_RESERVED إن كان الاسم من الأسماء التي تحتفظ بها نقرة لنفسها.
افتح في المرجعPOST /linksGET/linksعرض الروابط
يعرض روابط مساحة العمل صفحة بعد صفحة. يحوي الرد items وnextCursor: أرسل nextCursor في cursor لجلب الصفحة التالية، وقيمته null في الصفحة الأخيرة.
| المعامل | الوصف |
|---|---|
cursor | قيمة nextCursor من الصفحة السابقة. اتركه فارغاً للصفحة الأولى. |
limit | عدد الروابط في الصفحة، من 1 إلى 100. الافتراضي 25. |
sort | created (الافتراضي) أو clicks أو name. |
status | عرض الروابط في هذه الحالة فقط: active أو expiring أو expired أو capped أو disabled أو blocked. |
tag | عرض الروابط التي تحمل هذا الوسم فقط. |
q | نص يُبحث عنه في الاسم والوجهة والعنوان والوسوم، حتى 100 حرف. |
await nqra("GET", "/links?limit=25&sort=clicks&tag=courses");{
"items": [{ "slug": "python-101", "url": "https://…", "clickCount": 1846, "tags": [{ "id": "tag_…", "name": "courses", "color": "#0d6b88" }], … }],
"nextCursor": null
}GET /linksPATCH/links/:slugتعديل رابط
يغيّر واحداً أو أكثر من: url وtitle وtags وexpiresAt وmaxClicks وisActive. أرسل null لمسح title أو expiresAt أو maxClicks. لا يمكن تغيير الاسم. يرجع 400 NO_FIELDS إن لم ترسل أي حقل.
| الحقل | النوع | الوصف |
|---|---|---|
url | string | الوجهة. يجب أن تبدأ بـ http:// أو https://. |
title | string | null | عنوان لتمييز الرابط عندك، حتى 200 حرف. أرسل null لمسحه عند التعديل. |
tags | string[] | قائمة وسوم تُحفظ بأحرف صغيرة. |
expiresAt | number | null | وقت الانتهاء بالمللي ثانية (Unix). يجب أن يكون في المستقبل. |
maxClicks | number | null | عدد صحيح موجب. بعد بلوغه يتوقف التحويل. |
isActive | boolean | false يوقف الرابط مؤقتاً وtrue يعيده. |
await nqra("PATCH", "/links/python-101", { isActive: false });
// → 200 with the updated linkPATCH /links/:slugDELETE/links/:slugحذف رابط
يحذف الرابط حذفاً ناعماً: يتوقف التحويل فوراً وتبقى تحليلاته، ويبقى الاسم محجوزاً. يرجع 204 بلا محتوى.
افتح في المرجعDELETE /links/:slugGET/stats/links/:slugإحصاءات رابط
الإجماليات والسلسلة الزمنية والتوزيعات (الدول والمدن ومصادر الزيارة والأجهزة والمتصفحات والأنظمة) لرابط واحد.
| المعامل | الوصف |
|---|---|
range | 24h أو 7d (الافتراضي) أو 30d أو 90d أو 365d أو all. الفترة الأطول مما تحفظه خطتك ترجع 403 PLAN_LIMIT. |
await nqra("GET", "/stats/links/python-101?range=7d");{
"slug": "python-101",
"range": "7d",
"clickCount": 1846,
"lastClickAt": 1790000000000,
"totals": { "clicks": 412, "prevClicks": 368 },
"series": { "values": [51, 62, …], "times": [1789395600000, …], "bucketMs": 86400000 },
"countries": [{ "key": "IQ", "value": 244 }, …],
"referrers": [{ "key": "instagram.com", "value": 118 }, …],
…
}GET /stats/links/:slugGET/stats/overviewإحصاءات مساحة العمل
الإجماليات والسلسلة الزمنية وأكثر الروابط نقراً والتوزيعات نفسها لمساحة العمل كلها.
| المعامل | الوصف |
|---|---|
range | 24h أو 7d (الافتراضي) أو 30d أو 90d أو 365d أو all. الفترة الأطول مما تحفظه خطتك ترجع 403 PLAN_LIMIT. |
await nqra("GET", "/stats/overview?range=30d");{
"range": "30d",
"totals": { "clicks": 5120, "prevClicks": 4380, "lifetimeClicks": 18240, … },
"series": { "values": [160, 171, …], "times": [1787400000000, …], "bucketMs": 86400000 },
"topLinks": [{ "slug": "python-101", "clicks": 1846, "spark": [51, 62, …] }],
"countries": [{ "key": "IQ", "value": 2210 }, …],
…
}GET /stats/overviewالتحويل
عند فتح nqra.link/<slug> يُحوَّل الزائر بالرمز 302 إلى الوجهة.
- تُسجَّل النقرة مع البلد والمدينة والجهاز والمتصفح ومصدر الزيارة.
- زيارات محركات البحث ومعاينات الروابط تُحوَّل لكنها لا تُحتسب.
- حد النقرات وتاريخ الانتهاء يُتحقق منهما مع كل نقرة، فلا يُتجاوز الحد حتى مع النقرات المتزامنة.
- الروابط المنتهية وتلك التي بلغت حدها والمتوقفة والمحظورة تعرض صفحة توضّح السبب بدل التحويل.