الويبهوك
احصل على إشعار موقَّع عند انتهاء عملية توليد في Direct API، وتحقق منه، واقرأ عملية التوليد للاطلاع على تفاصيلها.
الويبهوك نقطة نهاية HTTPS خاصة بك تستدعيها Morphic عندما تبلغ عملية توليد حالة نهائية. التسليمات موقَّعة، ويُعاد إرسالها لمدة يوم تقريبًا، وتُسجَّل. كل حدث إشعار مقتضب: يذكر أي عملية توليد انتهت وكيف، ثم تقرأ عملية التوليد بمفتاحك للاطلاع على أصولها وفوترتها ورسالة الخطأ.
تسجيل نقطة نهاية
يحتاج POST /v1/direct/webhooks إلى النطاق generations:write.
curl -s https://mcp.morphic.com/v1/direct/webhooks \
-H "Authorization: Bearer $MORPHIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/morphic",
"events": ["generation.succeeded", "generation.failed", "generation.cancelled"],
"description": "Production order pipeline"
}'| الحقل | القواعد |
|---|---|
url | HTTPS على مضيف عام (بلا عناوين IP حرفية، وبلا عناوين خاصة أو محلية)، حتى 2,048 حرفًا |
events | نوع حدث واحد أو أكثر |
description | اختياري، حتى 200 حرف |
الاستجابة هي 201:
{
"webhook": {
"id": "01929a10-0c3d-7f44-8a21-0b1c2d3e4f50",
"url": "https://hooks.example.com/morphic",
"events": ["generation.succeeded", "generation.failed", "generation.cancelled"],
"description": "Production order pipeline",
"created_at": "2026-10-25T08:00:00.000Z",
"signing_secret": "whsec_4b1e…"
}
}- لا يظهر
signing_secretإلا في هذه الاستجابة. خزّنه كما تخزّن مفتاح API. - لتدوير السر، سجّل نقطة نهاية جديدة، وانقل استدعاءاتك إلى معرّفها، ثم احذف القديمة.
- يجوز للمؤسسة أن تحتفظ بما يصل إلى 10 نقاط نهاية.
إدارة نقاط النهاية
| الطلب | النطاق | الوظيفة |
|---|---|---|
GET /v1/direct/webhooks | assets:read | يسرد نقاط النهاية بصيغة { "webhooks": [ … ] }، دون أسرارها أبدًا |
DELETE /v1/direct/webhooks/{webhook_id} | generations:write | يزيل نقطة النهاية؛ وتُترك التسليمات المعلقة إليها |
ربط نقطة نهاية باستدعاء
مرّر webhook_id في جسم استدعاء الأداة. تُسلَّم كل عملية توليد يبدأها ذلك الاستدعاء إلى نقطة النهاية تلك عندما تبلغ حالة نهائية اشتركت فيها نقطة النهاية. والاستدعاءات التي لا تحمل webhook_id لا ترسل أي ويبهوك.
الأدوات التي تعرض الفيديو على خوادم Morphic (video_compose وتحويلات video_* وburn_subtitles) لا تقبل webhook_id بعد؛ استطلع عمليات التوليد الخاصة بها.
أنواع الأحداث
| الحدث | يُرسَل عندما |
|---|---|
generation.succeeded | انتهت عملية التوليد بمخرجات |
generation.failed | فشلت عملية التوليد؛ ويُسترد المبلغ المخصوم |
generation.cancelled | أُلغيت عملية التوليد؛ ويُسترد المبلغ المخصوم |
- تنتج كل عملية توليد حدثًا واحدًا على الأكثر.
- لا تُسلَّم
queuedوin_progress؛ استطلعها إن كنت تحتاجها. - تُراقَب عملية التوليد لمدة 72 ساعة بعد بدئها. والتي تنتهي بعد ذلك لا ترسل أي حدث، فاقرأها بدلًا من ذلك.
التسليم
POST /morphic HTTP/1.1
Host: hooks.example.com
Content-Type: application/json
User-Agent: Morphic-Webhooks/1.0
Morphic-Event-Id: 0192a7c0-5d4e-7b3a-8c2d-1e0f9a8b7c6d
Morphic-Delivery-Id: 0192a7c0-6e5f-7c4b-9d3e-2f1a0b9c8d7e
Morphic-Event-Type: generation.succeeded
Morphic-Signature: t=1792919741,v1=5f8a0c…e21b
{
"id": "0192a7c0-5d4e-7b3a-8c2d-1e0f9a8b7c6d",
"type": "generation.succeeded",
"created_at": "2026-10-25T09:15:42.410Z",
"api_version": "v1",
"data": {
"generation": {
"object": "generation",
"id": "0192a7b3-a1c4-7e02-8f9d-1a2b3c4d5e6f",
"tool": "generate_video",
"status": "succeeded",
"completed_at": "2026-10-25T09:15:41.902Z",
"error_code": null,
"metadata": { "order_id": "4411" }
}
}
}لا يحمل data.generation إلا هذه الحقول:
| الحقل | المعنى |
|---|---|
object، id، tool، status، completed_at، metadata | كما في كائن عملية التوليد |
error_code | null، أو رمز عملية توليد في حالة failed |
لا يحمل الحدث أبدًا المخرجات أو الروابط أو الفوترة أو النموذج أو رسالة الخطأ، لذا فإن التسليم الذي يصل إلى المكان الخطأ أو إلى سجل لا يكشف شيئًا. عند الاستلام، اقرأ عملية التوليد بمفتاحك: GET /v1/direct/generations/{id}، أو القراءة المجمّعة لعدة عمليات. وبحلول وقت إرسال الحدث لا يتبقى شيء مستحق على فوترته، لذا تكون تلك القراءة نهائية.
| الترويسة | المعنى |
|---|---|
Morphic-Event-Id | معرّف الحدث، متطابق في كل إعادة محاولة؛ أزِل التكرار بناءً عليه |
Morphic-Delivery-Id | هذه المحاولة بعينها؛ يختلف في كل إعادة محاولة |
Morphic-Event-Type | قيمة type في الجسم |
Morphic-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
يُرسَل الحدث عادةً في غضون دقيقة تقريبًا من بلوغ عملية التوليد حالتها النهائية. وهو ليس تدفقًا في الوقت الفعلي: للحصول على أقل زمن انتقال لعملية توليد واحدة تنتظرها، استطلعها استطلاعًا طويلًا.
التحقق من التوقيع
v1 هو HMAC-SHA256 بالصيغة الست عشرية، بمفتاح signing_secret الخاص بنقطة النهاية، للسلسلة {t}.{raw request body}.
- قسّم الترويسة عند
,إلىtوv1. - احسب
HMAC_SHA256(secret, t + "." + raw_body)على البايتات الخام التي استلمتها، قبل أي تحليل لـ JSON أو إعادة تسلسل. - قارنه بـ
v1في زمن ثابت. - ارفض التسليم إذا كان
tيبعد أكثر من 5 دقائق عن الوقت الحالي، لمنع إعادة الإرسال.
import crypto from 'node:crypto';
import express from 'express';
const app = express();
app.post('/morphic', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.get('Morphic-Signature') ?? '';
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const expected = crypto
.createHmac('sha256', process.env.MORPHIC_WEBHOOK_SECRET)
.update(`${parts.t}.${req.body}`)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300;
const valid =
parts.v1?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!fresh || !valid) return res.sendStatus(400);
const event = JSON.parse(req.body);
enqueue(event); // process asynchronously, keyed by event.id
res.sendStatus(204);
});نقطة النهاية غير المتحقق منها باب مفتوح: يستطيع أي شخص يعرف عنوان URL الخاص بها أن يخبرك بأن عملية توليد قد انتهت. تحقق من كل توقيع، وارفض أي طابع زمني يزيد عمره على 5 دقائق.
الرد وإعادة المحاولات
- أجب بأي
2xxخلال 10 ثوانٍ، ثم أنجز العمل. - أي شيء آخر محاولة فاشلة: حالة غير
2xx، أو انتهاء المهلة، أو رفض الاتصال، أو خطأ TLS. - لا تُتبَع عمليات إعادة التوجيه؛ وتُعد
3xxمحاولة فاشلة. - الترتيب غير مضمون، وقد يصل الحدث أكثر من مرة. اجعل المعالج لديك آمنًا للتكرار بناءً على
Morphic-Event-Id، أو علىdata.generation.id، لأن لكل عملية توليد حدثًا واحدًا على الأكثر.
يُعاد إرسال المحاولة الفاشلة بعد:
| إعادة المحاولة | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| الانتظار بعد المحاولة السابقة | 1 دقيقة | 5 دقائق | 15 دقيقة | 1 ساعة | 3 ساعات | 6 ساعات | 12 ساعة |
بعد إعادة المحاولة السابعة، أي بعد نحو 22 ساعة من المحاولة الأولى، يُترك الحدث. ولا تتأثر عملية التوليد نفسها: اقرأها عبر GET /v1/direct/generations/{id}.
سجل التسليم
يعيد GET /v1/direct/webhooks/{webhook_id}/events (النطاق assets:read) أحدث 20 حدثًا لنقطة النهاية، لكل منها الجسم المرسَل بالضبط ونتيجة كل محاولة. أضف ?generation_id=… لأحداث عملية توليد واحدة.
{
"webhook_events": [
{
"id": "0192a7c0-5d4e-…",
"type": "generation.succeeded",
"generation_id": "0192a7b3-…",
"status": "delivered",
"created_at": "2026-10-25T09:15:42.410Z",
"payload": { "…": "the body that was sent" },
"attempts": [
{ "id": "0192a7c0-6e5f-…", "attempted_at": "2026-10-25T09:15:42.900Z", "response_status": 204, "duration_ms": 131, "error": null, "response_body_excerpt": null }
]
}
]
}status الحدث | المعنى |
|---|---|
pending | لم يُسلَّم بعد؛ وقد تتبعه محاولات أخرى |
delivered | أجابت نقطة النهاية لديك بـ 2xx |
abandoned | فشلت آخر إعادة محاولة، أو أُزيلت نقطة النهاية |
skipped | لم تشترك نقطة النهاية في نوع الحدث ذلك |
الويبهوك هو الإشارة الأرخص والأسرع، لا الضمان. احتفظ باستطلاع عرضي لعمليات التوليد التي لم تتلقَّ خبرها كشبكة أمان.
إذا واجهت أي مشكلة أو كانت لديك أي أسئلة، فلا تتردد في التواصل معنا. يسعدنا مساعدتك. اكتب لنا على support@morphic.com.