Webhooks

احصل على مفتاح API

تسجيل webhook

سجّل عنوان https عامًا والأحداث التي تريدها. يظهر سرّ التوقيع (whsec_…) في هذا الجواب فقط. يملك التطبيق حتى 10 webhooks.

bash
curl -X POST https://api.sofia-post.com/api/v1/webhooks \
  -H "Authorization: Bearer $SOFIA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://app.example.com/hooks/sofia","events":["post.published","post.failed"]}'

الأحداث

الحدثdata
post.publishedpostId, establishmentId, platform, publishedAt, permalink
post.failedpostId, establishmentId, platform, error
webhook.testwebhookId

ترسل Sofia كل حدث بـ POST بصيغة JSON { id, type, createdAt, data }، مع الترويسات Sofia-Event-Id وSofia-Event-Type وSofia-Signature. لا يُعلَن إلا عن المنشورات التي أنشأها تطبيقك.

التحقق من التوقيع

Sofia-Signature هو t=<unix time>,v1=<hex>، حيث v1 هو HMAC-SHA256 للقيمة <t>.<raw body> بسرّك. تحقق منه على الجسم الخام، وارفض أي طابع زمني قديم:

javascript
import { createHmac, timingSafeEqual } from 'node:crypto';

const isSignedBySofia = (header, rawBody, secret) => {
  const parts = Object.fromEntries(
    (header ?? '').split(',').map((part) => part.trim().split('=', 2)),
  );
  const timestamp = Number(parts.t);
  if (!Number.isInteger(timestamp) || typeof parts.v1 !== 'string') return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
  const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest();
  const received = Buffer.from(parts.v1, 'hex');
  return received.length === expected.length && timingSafeEqual(received, expected);
};

التسليم وإعادة المحاولة

  • الجواب 2xx يعني أن الحدث سُلّم. أي جواب آخر، أو إعادة توجيه (لا تُتبع أبدًا)، أو 10 ثوانٍ دون جواب، يعيد المحاولة بعد دقيقة، ثم 5 دقائق، ثم 30 دقيقة، ثم ساعتين، بحد أقصى 5 محاولات.
  • قد يصل الحدث نفسه مرتين: أزل التكرار بالاعتماد على Sofia-Event-Id.
  • أجب بسرعة وعالج الحدث بعد ذلك.

يرسل POST /v1/webhooks/{id}/test حدث webhook.test، موقّعًا مثل غيره.