تخطَّ إلى المحتوى

واجهة نقرة البرمجية

أنشئ الروابط القصيرة وعدّلها واقرأ تحليلاتها من متجرك أو خادمك. كل الطلبات والردود بصيغة JSON، وكل طلب يحمل مفتاح API لمساحة العمل.

العنوان الأساسي
https://api.nqra.link/api/v1
الصيغة
application/json
حد الطلبات
600 طلب كل 60 ثانية لكل مفتاح API. عند تجاوزها تصلك 429؛ انتظر المدة في Retry-After ثم أعد المحاولة.

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

المصادقة

أرسل بيانات الاعتماد مع كل طلب في إحدى هاتين الترويستين:

الترويسةالقيمة
x-api-keynq_live_… مفتاح API لمساحة عملك.
AuthorizationBearer <token> رمز وصول OAuth 2.1 أو رمز جلسة. أرسله بدلاً من المفتاح لا معه.

أنشئ المفاتيح من لوحة التحكم في «للمطوّرين» ثم «مفاتيح API». المفتاح يتبع مساحة عمل لا شخصاً، ولا يملك إلا الصلاحيات التي تمنحها له. الواجهة البرمجية جزء من الخطط المدفوعة.

تستخدم كل الأمثلة في هذه الصفحة هذه الدالة الصغيرة:

JavaScript (Workers, Node 20+, Bun)
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
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 · Bearer
curl "https://api.nqra.link/api/v1/links" -H "authorization: Bearer $ACCESS_TOKEN"
احفظ المفتاح على الخادم فقط. من يملكه يستطيع تنفيذ ما تسمح به صلاحياته في مساحة عملك. إن تسرّب المفتاح فألغِه من صفحة مفاتيح API.

الأخطاء

عند الخطأ يرجع رمز حالة HTTP وجسم فيه كائن error: رمز ثابت code ورسالة message وأحياناً details. اعتمد على code فالرسائل قد تتغير.

الرد409
{ "error": { "code": "SLUG_TAKEN", "message": "Slug already taken." } }
الحالةالرمزالمعنى
400AMBIGUOUS_CREDENTIALSأُرسل نوعان من بيانات الاعتماد معاً، مثل جلسة ومفتاح API. أرسل نوعاً واحداً.
400DOMAIN_APEXالنطاق الرئيسي لا يصلح نطاقاً مخصصاً؛ استخدم نطاقاً فرعياً مثل ⁦go.example.com⁩.
400DOMAIN_INVALIDاسم النطاق غير صالح.
400DOMAIN_RESERVEDالنطاق محجوز لنقرة.
400MAX_CLICKS_BELOW_COUNTقيمة maxClicks أقل من عدد النقرات المسجلة على الرابط.
400NO_FIELDSأُرسل تعديل بلا أي حقل للتغيير.
400URL_REJECTEDعنوان الوجهة غير مسموح. يوضح details.reason السبب.
400VALIDATION_FAILEDجسم الطلب أو معاملاته أو مساره غير صالح. يسرد details كل مشكلة.
401API_KEY_INVALIDمفتاح API خاطئ أو منتهي أو مُلغى.
401UNAUTHENTICATEDلم تُرسل بيانات اعتماد، أو انتهت صلاحيتها.
403EMAIL_NOT_VERIFIEDلم يُؤكَّد البريد الإلكتروني للحساب بعد.
403FORBIDDENالمفتاح أو الرمز لا يملك الصلاحية التي يحتاجها هذا الطلب.
403PLAN_LIMITخطة مساحة العمل لا تشمل هذه الميزة. يحدد details الميزة.
404LINK_NOT_FOUNDالرابط غير موجود في مساحة العمل هذه.
404NOT_FOUNDالمورد غير موجود في مساحة العمل هذه.
409ALREADY_MEMBERالشخص عضو في مساحة العمل بالفعل.
409DOMAIN_TAKENالنطاق مستخدم ولا يمكن تسجيله مرة أخرى.
409DOWNGRADE_BLOCKEDالاستخدام الحالي أكبر مما تسمح به الخطة الجديدة. يسرد details.over ما يجب تقليله.
409NO_ACTIVE_ORGلا توجد مساحة عمل نشطة في الجلسة.
409SLUG_RESERVEDاسم الرابط من الأسماء التي تحتفظ بها نقرة لنفسها.
409SLUG_TAKENاسم الرابط مستخدم. الروابط المحذوفة تبقى أسماؤها محجوزة.
409TAG_EXISTSيوجد وسم بهذا الاسم.
409VERSION_MISMATCHتغيّر السجل أثناء تنفيذ الطلب. اقرأه من جديد ثم أعد المحاولة.
429QUOTA_EXCEEDEDاستهلكت مساحة العمل حصتها من هذه الميزة. يحوي details الميزة والحد، وما تبقى إن عُرف.
429RATE_LIMITEDطلبات كثيرة. انتظر عدد الثواني في ترويسة Retry-After.
500INTERNALحدث خطأ لدينا. أعد المحاولة، وإن تكرر تواصل مع الدعم.
502UPSTREAM_FAILEDتعطلت خدمة نعتمد عليها. أعد المحاولة.
503ANALYTICS_UNAVAILABLEالتحليلات غير متاحة مؤقتاً. أعد المحاولة بعد قليل.
503BILLING_UNAVAILABLEالفوترة غير متاحة مؤقتاً.
503DOMAINS_UNAVAILABLEالنطاقات المخصصة غير متاحة مؤقتاً.
503SLUG_GENERATION_FAILEDتعذّر إيجاد اسم عشوائي متاح. أعد المحاولة.

حد الطلبات

600 طلب كل 60 ثانية لكل مفتاح API. عند تجاوزها تصلك 429؛ انتظر المدة في Retry-After ثم أعد المحاولة.

الرد429
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://⁩.
slugstringاسم الرابط: من 3 إلى 64 حرفاً من A-Z وa-z و0-9 و- و_.
titlestringعنوان لتمييز الرابط عندك، حتى 200 حرف. أرسل null لمسحه عند التعديل.
tagsstring[]قائمة وسوم تُحفظ بأحرف صغيرة.
expiresAtnumberوقت الانتهاء بالمللي ثانية (Unix). يجب أن يكون في المستقبل.
maxClicksnumberعدد صحيح موجب. بعد بلوغه يتوقف التحويل.
الطلب
await nqra("POST", "/links", {
  url: "https://rawafid.manhali.com/courses/python-basics",
  slug: "python-101",
  tags: ["courses"],
  maxClicks: 500,
});
الرد201
{
  "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 /links

GET/linksعرض الروابط

يعرض روابط مساحة العمل صفحة بعد صفحة. يحوي الرد items وnextCursor: أرسل nextCursor في cursor لجلب الصفحة التالية، وقيمته null في الصفحة الأخيرة.

المعاملالوصف
cursorقيمة nextCursor من الصفحة السابقة. اتركه فارغاً للصفحة الأولى.
limitعدد الروابط في الصفحة، من 1 إلى 100. الافتراضي 25.
sortcreated (الافتراضي) أو clicks أو name.
statusعرض الروابط في هذه الحالة فقط: active أو expiring أو expired أو capped أو disabled أو blocked.
tagعرض الروابط التي تحمل هذا الوسم فقط.
qنص يُبحث عنه في الاسم والوجهة والعنوان والوسوم، حتى 100 حرف.
الطلب
await nqra("GET", "/links?limit=25&sort=clicks&tag=courses");
الرد200
{
  "items": [{ "slug": "python-101", "url": "https://…", "clickCount": 1846, "tags": [{ "id": "tag_…", "name": "courses", "color": "#0d6b88" }], … }],
  "nextCursor": null
}
افتح في المرجعGET /links

PATCH/links/:slugتعديل رابط

يغيّر واحداً أو أكثر من: url وtitle وtags وexpiresAt وmaxClicks وisActive. أرسل null لمسح title أو expiresAt أو maxClicks. لا يمكن تغيير الاسم. يرجع 400 NO_FIELDS إن لم ترسل أي حقل.

الحقلالنوعالوصف
urlstringالوجهة. يجب أن تبدأ بـ ⁦http://⁩ أو ⁦https://⁩.
titlestring | nullعنوان لتمييز الرابط عندك، حتى 200 حرف. أرسل null لمسحه عند التعديل.
tagsstring[]قائمة وسوم تُحفظ بأحرف صغيرة.
expiresAtnumber | nullوقت الانتهاء بالمللي ثانية (Unix). يجب أن يكون في المستقبل.
maxClicksnumber | nullعدد صحيح موجب. بعد بلوغه يتوقف التحويل.
isActivebooleanfalse يوقف الرابط مؤقتاً وtrue يعيده.
الطلب
await nqra("PATCH", "/links/python-101", { isActive: false });
// → 200 with the updated link
افتح في المرجعPATCH /links/:slug

DELETE/links/:slugحذف رابط

يحذف الرابط حذفاً ناعماً: يتوقف التحويل فوراً وتبقى تحليلاته، ويبقى الاسم محجوزاً. يرجع 204 بلا محتوى.

افتح في المرجعDELETE /links/:slug

GET/stats/overviewإحصاءات مساحة العمل

الإجماليات والسلسلة الزمنية وأكثر الروابط نقراً والتوزيعات نفسها لمساحة العمل كلها.

المعاملالوصف
range24h أو 7d (الافتراضي) أو 30d أو 90d أو 365d أو all. الفترة الأطول مما تحفظه خطتك ترجع 403 PLAN_LIMIT.
الطلب
await nqra("GET", "/stats/overview?range=30d");
الرد200
{
  "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

GET/tagsالوسوم

وسوم مساحة العمل، لكل وسم لونه وعدد الروابط الفعّالة التي تحمله.

الطلب
await nqra("GET", "/tags");
الرد200
[{ "id": "tag_…", "name": "courses", "color": "#0d6b88", "linksCount": 6 }]
افتح في المرجعGET /tags

التحويل

عند فتح ⁦nqra.link/<slug>⁩ يُحوَّل الزائر بالرمز 302 إلى الوجهة.

  • تُسجَّل النقرة مع البلد والمدينة والجهاز والمتصفح ومصدر الزيارة.
  • زيارات محركات البحث ومعاينات الروابط تُحوَّل لكنها لا تُحتسب.
  • حد النقرات وتاريخ الانتهاء يُتحقق منهما مع كل نقرة، فلا يُتجاوز الحد حتى مع النقرات المتزامنة.
  • الروابط المنتهية وتلك التي بلغت حدها والمتوقفة والمحظورة تعرض صفحة توضّح السبب بدل التحويل.