API التوثيق
العنوان الأساسي هو https://yhfdghkh6544.com/v1. تستخدم جميع الواجهات HTTP القياسي، ويمكن تمرير المعلمات في سلسلة الاستعلام (GET) أو في جسم الطلب بصيغة JSON (POST).
البدء السريع
- سجّل مجانًا، ثم أنشئ مفتاحًا من صفحة «API Key» في لوحة التحكم.
- ضع المفتاح في ترويسة الطلب
X-Access-Key، ثم استدعِ واجهة لقطات الشاشة:
curl "https://yhfdghkh6544.com/v1/screenshot?url=https://example.com&full_page=true" \
-H "X-Access-Key: $SNAPI_KEY" \
-o screenshot.pngالمصادقة
يتطلب كل طلب API Key، ويمكن تمريره بإحدى الطرق التالية:
- ترويسة الطلب
X-Access-Key: snp_…(موصى بها للاستدعاءات من الخادم) - معلمة الاستعلام
access_key=snp_… - رابط URL موقّع (عند تضمين العنوان في صفحة ويب، دون كشف السر)
تظهر قيمة API Key مرة واحدة فقط عند إنشائه، لذا احفظها بأمان. إذا تسرّب المفتاح، يمكنك تعطيله من لوحة التحكم.
واجهة لقطات الشاشة
/v1/screenshot/v1/screenshotمعلمات خاصة بلقطات الشاشة:
| المعلمة | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
| format | enum | png | png أو jpeg أو webp. |
| device_scale_factor | number | 1 | معامل التحجيم، من 1–3. استخدم 2 للحصول على دقة Retina، بحجم ملف يقارب 4 أضعاف. |
| quality | integer | 80 | جودة JPEG / WebP، من 1–100. |
| full_page | boolean | false | التقاط الصفحة كاملةً. تُمرَّر الصفحة شاشةً تلو الأخرى لتفعيل التحميل الكسول، بارتفاع أقصى يبلغ 20,000 بكسل. |
| selector | string | — | التقاط أول عنصر يطابق محدّد CSS هذا فقط. لا يمكن استخدامها مع full_page. |
معلمات مشتركة بين لقطات الشاشة وPDF:
| المعلمة | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
| url | string | — | عنوان الصفحة المراد التقاطها، باستخدام http أو https. استخدم هذه المعلمة أو html، وليس كليهما. يُحتفظ بجزء العنوان الذي يبدأ بـ #، مما يتيح التقاط الصفحة المطلوبة مباشرةً في تطبيقات الصفحة الواحدة التي تستخدم التوجيه بالتجزئة، مثل https://app.com/#/report/1. |
| html | string | — | تمرير HTML مباشرةً (بحد أقصى 2 MB). متاح عبر POST فقط. |
| viewport_width | integer | 1280 | عرض إطار العرض، من 320–3840. يُستخدم عرض الأجهزة المحمولة عندما تكون القيمة أقل من 768. |
| viewport_height | integer | 800 | ارتفاع إطار العرض، من 200–3840. |
| wait_until | enum | networkidle | استراتيجية الانتظار: domcontentloaded (الأسرع، ومناسبة للصفحات الثابتة)، أو load، أو networkidle (تتتبّع جميع الطلبات منذ فتح الصفحة، ثم تلتقط الصورة بعد تحميل الصفحة ومرور 500 مللي ثانية متواصلة دون طلبات جارية، مع انتظار إضافي لا يتجاوز 8 ثوانٍ؛ مناسبة لتطبيقات الصفحة الواحدة). |
| wait_for_selector | string | — | بعد تحميل الصفحة، تنتظر ظهور عنصر يطابق محدّد CSS هذا ويكون مرئيًا قبل الالتقاط، لمدة تصل إلى 10 ثوانٍ. إذا لم يظهر، تُرجع selector_not_found دون احتسابه من الحصة. مناسبة لتطبيقات الصفحة الواحدة التي تؤخّر عرض المحتوى باستخدام المؤقتات أو الرسوم المتحركة بدلًا من طلبات الشبكة، مثل .chart-ready. |
| delay | integer | 0 | تأخير إضافي بالمللي ثانية بعد انتهاء الانتظار، من 0–10000. يُستخدم لانتظار الرسوم المتحركة أو المكوّنات ذات التحميل الكسول. |
| block_ads | boolean | true | حظر الطلبات إلى نطاقات الإعلانات والتتبّع. |
| block_cookie_banners | boolean | true | إخفاء نوافذ الموافقة على ملفات تعريف الارتباط. |
| dark_mode | boolean | false | محاكاة prefers-color-scheme: dark. |
| hide_selectors | string | — | قائمة بمحدّدات CSS للعناصر المراد إخفاؤها، مثل .ad,#popup. |
| cache | boolean | true | تحديد ما إذا كان يجب البحث في الذاكرة المؤقتة. عند ضبطها على false، تُعاد عملية العرض، وتُحفظ النتيجة في الذاكرة المؤقتة أيضًا. |
| cache_ttl | integer | 86400 | مدة صلاحية التخزين المؤقت بالثواني، من 60–2592000. |
| response_type | enum | binary | تُرجع binary الملف مباشرةً؛ وتُرجع json عنوان الملف والبيانات الوصفية. |
التقاط تطبيقات الصفحة الواحدة (React وVue وغيرها):تُشغَّل JavaScript في متصفح حقيقي قبل التقاط الصفحة. تنتظر الاستراتيجية الافتراضية networkidle اكتمال جلب البيانات. إذا كان المحتوى يُعرض بعد انتهاء الطلبات باستخدام مؤقتات أو رسوم متحركة، فأضف wait_for_selector لتحديد عنصر يدل على جاهزية المحتوى. وإذا لم تجد عنصرًا مناسبًا، فاستخدم delay لإضافة وقت انتظار.
واجهة PDF
/v1/pdf/v1/pdfتُحتسب كل عملية PDF بمقدار 2 من الحصة. تُمرَّر الصفحة كاملةً مرة واحدة قبل الطباعة لتفعيل المحتوى ذي التحميل الكسول. إضافةً إلى المعلمات المشتركة، تتوفر المعلمات التالية:
| المعلمة | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
| paper | enum | a4 | حجم الورق: a4 أو letter. إذا كانت الصفحة تتضمن قاعدة @page، فتُعطى الأولوية لإعداداتها. |
| print_background | boolean | true | طباعة ألوان الخلفية وصورها. |
| pdf_media | enum | تستخدم print أنماط الطباعة؛ وتستخدم screen أنماط الشاشة (كما تظهر على الشاشة). |
curl -X POST "https://yhfdghkh6544.com/v1/pdf" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>التقرير ربع السنوي</h1><p>نص التقرير…</p>", "paper": "a4"}' \
-o report.pdfالاستجابة
افتراضيًا (response_type=binary)، يُرجع الملف مباشرةً، وتكون قيمة Content-Type مطابقةً لصيغته. ترويسات الاستجابة:
X-Request-Id: معرّف هذا الطلب؛ يُرجى تزويدنا به عند استكشاف المشكلاتX-Snapi-Cache: HITأوMISSX-Snapi-Truncated: true: اقتُطعت الصفحة الكاملة لتجاوز ارتفاعها 20,000 بكسلX-Snapi-Format-Changed: webp: يُحوَّل PNG تلقائيًا إلى WebP إذا تجاوز 5 MB (لا يحدث التحويل عند تحديد format=png صراحةً)
عند تعيين response_type=json، يُرجع عنوان الملف والبيانات الوصفية:
curl -X POST "https://yhfdghkh6544.com/v1/screenshot" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "response_type": "json"}'
# الاستجابة
{
"url": "https://yhfdghkh6544.com/i/3f/3f9c….png",
"cache_hit": false,
"duration_ms": 1284,
"format": "png",
"width": 1280,
"height": 800,
"request_id": "req_01j…"
}روابط URL الموقّعة
هل تريد وضع عنوان لقطة الشاشة مباشرةً في <img src> دون كشف API Key؟ احسب التوقيع على خادمك باستخدام السر المرتبط بالمفتاح (يمكنك الاطّلاع عليه في صفحة API Key بلوحة التحكم):
canonical = رتّب جميع المعلمات، باستثناء signature، ترتيبًا معجميًا حسب أسمائها،
ونسّق كل عنصر بالشكل k=urlencode(v) (وفق RFC 3986، مع ترميز المسافة إلى %20)، ثم صِل العناصر باستخدام &
signature = hex(HMAC-SHA256(secret, canonical))يُعدّ التوقيع الصحيح مصادقةً صالحة. يؤدي تغيير أي معلمة (مثل url) إلى إبطال التوقيع. تُضمَّن المعلمة الاختيارية expires (بالثواني وفق توقيت Unix) في التوقيع، وتُرجع الاستجابة signature_expired بعد انتهاء الصلاحية. لتحديث الذاكرة المؤقتة، غيّر معلمة لا تؤثر في النتيجة (مثل v=2) وأعِد التوقيع. تدعم روابط URL الموقّعة GET فقط.
import crypto from "node:crypto";
// ترميز RFC 3986 (المسافة هي %20)، ويجب أن يطابق قواعد الخادم
const enc = (v) =>
encodeURIComponent(v).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
function signedUrl(params, accessKey, secret) {
const all = { ...params, access_key: accessKey };
const canonical = Object.keys(all).sort().map((k) => `${k}=${enc(String(all[k]))}`).join("&");
const signature = crypto.createHmac("sha256", secret).update(canonical).digest("hex");
return `https://yhfdghkh6544.com/v1/screenshot?${canonical}&signature=${signature}`;
}
const src = signedUrl({ url: "https://example.com", viewport_width: 1200 }, KEY, SECRET);
// <img src={src} alt="معاينة صفحة الويب" />التخزين المؤقت
تُستخدم النتيجة المخزّنة مؤقتًا للطلبات ذات المعلمات المتطابقة (يُعدّ حذف المعلمة وتمرير قيمتها الافتراضية صراحةً متكافئين؛ ولا تدخل معلمات المصادقة والتخزين المؤقت في المقارنة). عند العثور على نتيجة مخزّنة، يُرجع الوضع الثنائي إعادة توجيه 302 إلى عنوان الملف مع Cache-Control، ويتبع المتصفح إعادة التوجيه ويخزّن الملف تلقائيًا؛ أما وضع JSON فيُرجع cache_hit: true.
لا تُحتسب النتائج المسترجعة من الذاكرة المؤقتة من الحصة.تُنفَّذ عملية عرض واحدة فقط للطلبات المتزامنة ذات المعلمات نفسها.
الحدود والفوترة
- تُحتسب فقط الطلبات الناجحة (2xx) التي لا تستخدم نتيجة مخزّنة مؤقتًا: 1 للقطة الشاشة، و2 لملف PDF.
- لا تُخصم حصة عند انتهاء المهلة، أو فشل العرض، أو أخطاء الموقع المستهدف، أو أخطاء المعلمات، أو فشل المصادقة.
- تُجدَّد الحصة كل شهر تقويمي حسب UTC. تتضمن الخطة المجانية 100 عملية شهريًا، وتُرجع quota_exceeded عند نفادها.
- عند تجاوز حد الطلبات في الثانية أو حد التزامن، تُرجع الاستجابة 429، وتحدّد الترويسة Retry-After مدة الانتظار المقترحة بالثواني.
- المدة القصوى للعرض 30 ثانية؛ والحد الأقصى لتنزيلات الصفحة الواحدة 50 MB؛ والحد الأقصى لحجم الملف الناتج 50 MB.
للاطّلاع على الحدود التفصيلية لكل خطة: الأسعار.
رموز الأخطاء
تُرجع جميع استجابات الأخطاء بصيغة JSON:
{
"error": {
"code": "render_failed",
"message": "target responded with an error status",
"upstream_status": 404,
"request_id": "req_01j…"
}
}| HTTP | code | المعنى | يُحتسب من الحصة |
|---|---|---|---|
| 400 | invalid_params | معلمة مفقودة أو خارج النطاق؛ تحدّد message المعلمة المعنية | لا |
| 400 | html_too_large | يتجاوز html حجم 2 MB | لا |
| 401 | unauthorized | API Key مفقود أو غير صالح أو معطّل | لا |
| 401 | signature_invalid | التوقيع غير مطابق (تغيّرت المعلمات أو كان السر غير صحيح) | لا |
| 401 | signature_expired | انتهت صلاحية رابط URL الموقّع بعد الوقت المحدّد في expires | لا |
| 403 | url_blocked | لا يُسمح بالوصول إلى العنوان المستهدف (مثل عنوان شبكة داخلية أو localhost) | لا |
| 408 | render_timeout | تجاوز العرض 30 ثانية | لا |
| 422 | render_failed | أرجع الموقع المستهدف 4xx/5xx، أو فشل DNS، أو حدث خطأ في الشهادة؛ تتضمن الاستجابة upstream_status | لا |
| 422 | selector_not_found | لم يطابق selector أي عنصر، أو انتهت مهلة انتظار wait_for_selector | لا |
| 422 | too_many_redirects | تجاوز عدد عمليات إعادة التوجيه 5 | لا |
| 429 | rate_limited | تم تجاوز حد الطلبات في الثانية؛ أعِد المحاولة وفق Retry-After | لا |
| 429 | concurrency_exceeded | تم تجاوز حد الطلبات المتزامنة | لا |
| 429 | quota_exceeded | نفدت الحصة الشهرية (الخطة المجانية) | لا |
| 429 | too_many_batches | تجاوز عدد المهام الدفعية غير المكتملة في الوقت نفسه 5 | لا |
| 500 | internal | خطأ في الخادم؛ تواصل معنا وأرفق request_id | لا |
المعالجة الدفعية غير المتزامنة
/v1/batch/v1/batch/{id}أرسل من 1–100 عنوان في طلب واحد، وستُرجع الواجهة معرّف المهمة فورًا (HTTP 202)، ثم تُلتقط الصفحات تباعًا في الخلفية. يناسب ذلك التقاط دفعات من الصفحات دون إبقاء الاتصال مفتوحًا. يمكنك الاستعلام دوريًا عن الحالة، أو تحديد webhook_url لتلقّي إشعار منا عند اكتمال جميع العمليات. تُستخدم طريقة المصادقة نفسها الخاصة بالواجهة المتزامنة (عبر ترويسة الطلب أو معلمة access_key فقط؛ روابط URL الموقّعة غير مدعومة).
| المعلمة | النوع | القيمة الافتراضية | الوصف |
|---|---|---|---|
| type | enum | screenshot | screenshot (لقطة شاشة) أو pdf. |
| urls | string[] | — | عناوين الصفحات المراد معالجتها، من 1–100 عنوان. إذا كان أي عنوان غير صالح، يُرجع الطلب بأكمله 400، وتحدّد message ترتيب العنوان غير الصالح. |
| options | object | {} | معلمات مشتركة لجميع العناوين، وهي نفسها معلمات الواجهة المتزامنة (مثل full_page وformat وviewport_width وcache_ttl). لا يجوز أن تتضمن url أو html أو response_type. |
| webhook_url | string | — | اختيارية. عنوان إرسال الإشعار عند اكتمال جميع العمليات. راجع «إشعار الاكتمال». |
curl -X POST "https://yhfdghkh6544.com/v1/batch" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "screenshot",
"urls": ["https://example.com", "https://example.org"],
"options": { "full_page": true, "format": "webp" },
"webhook_url": "https://your-app.com/hooks/snapi"
}'
# الاستجابة 202
{
"id": "bat_01j…",
"type": "screenshot",
"status": "queued",
"total": 2, "succeeded": 0, "failed": 0,
"created_at": "2026-10-18T09:30:00Z", "completed_at": null,
"webhook": { "url": "https://your-app.com/hooks/snapi", "status": "none", "attempts": 0 },
"items": [
{ "index": 0, "url": "https://example.com", "status": "pending", "result": null, "error": null },
{ "index": 1, "url": "https://example.org", "status": "pending", "result": null, "error": null }
]
}الاستعلام عن التقدّم: تنتقل حالة المهمة status بالترتيب من queued (في قائمة الانتظار) إلى running (قيد المعالجة)، ثم completed (اكتملت جميع العمليات، سواء نجحت أم فشلت). وتكون حالة كل عنوان pending أو running أو succeeded أو failed. عند النجاح، يظهر عنوان الملف في result؛ وعند الفشل، يظهر رمز الخطأ في error (وهو مطابق لرموز أخطاء الواجهة المتزامنة).
curl "https://yhfdghkh6544.com/v1/batch/bat_01j…" -H "X-Access-Key: $SNAPI_KEY"
{
"id": "bat_01j…",
"status": "completed",
"total": 2, "succeeded": 1, "failed": 1,
"completed_at": "2026-10-18T09:30:12Z",
"items": [
{
"index": 0, "url": "https://example.com", "status": "succeeded", "duration_ms": 1830,
"result": { "url": "https://yhfdghkh6544.com/i/3f/3f9c….webp", "mime": "image/webp", "width": 1280, "height": 2410, "cache_hit": false },
"error": null
},
{
"index": 1, "url": "https://example.org", "status": "failed", "duration_ms": 640,
"result": null,
"error": { "code": "render_failed", "message": "target responded with an error status" }
}
]
}- تُطبَّق قواعد الفوترة نفسها الخاصة بالواجهة المتزامنة: يُحتسب 1 لكل لقطة شاشة ناجحة و2 لكل ملف PDF ناجح، ولا تُخصم حصة للنتائج المخزّنة مؤقتًا أو العمليات الفاشلة.
- إذا كانت الحصة قد نفدت عند الإرسال، تُرجع الواجهة
quota_exceededفورًا. وإذا نفدت أثناء المعالجة، تفشل العناوين المتبقية بالرمزquota_exceeded. - يمكن لكل حساب تشغيل ما يصل إلى 5 مهام دفعية غير مكتملة في الوقت نفسه؛ ويُرجع
too_many_batchesعند تجاوز هذا الحد. - تحدّد
options.cache_ttlمدة صلاحية ملفات النتائج (الافتراضي يوم واحد). احرص على تنزيلها وحفظها قبل انتهاء صلاحيتها. - تُعرض قيمة
webhook.urlفي نتائج الاستعلام وإشعارات الاكتمال حتى المسار فقط، دون سلسلة الاستعلام.
إشعار الاكتمال
عند تحديد webhook_url، نرسل إليه طلب POST بعد اكتمال المهمة بالكامل. يكون جسم الطلب بصيغة JSON: { "event": "batch.completed", "batch": { … } }، ويطابق batch استجابة واجهة الاستعلام تمامًا. ترويسات الطلب:
X-Snapi-Signature: t=1760779812,v1=5d3f…: tهو وقت الإرسال (بالثواني وفق توقيت Unix)، وv1هو التوقيعX-Snapi-Event: batch.completedوX-Snapi-Delivery-Attempt: 1(رقم محاولة التسليم)
v1 = hex(HMAC-SHA256(secret, t + "." + نص الطلب الخام))
secret هو سر التوقيع المرتبط بـ API Key المستخدم عند إرسال المهمة (يمكنك عرضه في صفحة API Key في لوحة التحكم)- يجب إرجاع رمز حالة 2xx خلال 10 ثوانٍ، وإلا فستُعدّ المحاولة فاشلة. عند الفشل، تُعاد المحاولة بعد 10 ثوانٍ، ثم بعد 1 دقيقة، ثم بعد 5 دقائق (بحد أقصى 4 محاولات إجمالًا).
- في حالات نادرة جدًا، قد تتلقى إشعارات مكررة للمهمة نفسها. استخدم
batch.idلتجاهل التكرارات. - للتحقق من التوقيع، احسبه باستخدام البايتات الخام المستلمة، وتأكد من أن الفرق بين
tوالوقت الحالي لا يتجاوز بضع دقائق لمنع هجمات إعادة الإرسال. - يجب أن يكون عنوان رد الاتصال عنوان http(s) متاحًا عبر الإنترنت، ولا يجوز أن يشير إلى شبكة داخلية.
import crypto from "node:crypto";
// يجب أن يحتوي rawBody على البايتات الأصلية المستلمة، دون تحليلها باستخدام JSON.parse ثم إعادة تسلسلها
function verifySnapiWebhook(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // منع هجمات إعادة الإرسال
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const got = Buffer.from(parts.v1 ?? "");
return got.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), got);
}
// verifySnapiWebhook(req.rawBody, req.headers["x-snapi-signature"], SNAPI_SECRET)الاستعلام عن الاستخدام
/v1/usagecurl "https://yhfdghkh6544.com/v1/usage" -H "X-Access-Key: $SNAPI_KEY"
{ "month": "202610", "used": 37, "limit": 100, "remaining": 63, "overage": 0, "resets_at": "2026-11-01T00:00:00Z", ... }فحص سلامة الخدمة
/v1/healthلا يتطلب مصادقة، ويُرجع حالة العقدة وحالة مجموعة المتصفحات (الإجمالي، والمشغول، والمتاح).