Webhook
Dapatkan pemberitahuan bertanda tangan saat generasi Direct API selesai, verifikasi, lalu baca generasinya untuk detailnya.
Webhook adalah endpoint HTTPS milik Anda yang dipanggil Morphic ketika sebuah generasi mencapai status akhir. Pengiriman ditandatangani, diulang selama sekitar satu hari, dan dicatat. Setiap event adalah pemberitahuan ringkas: event menyebutkan generasi mana yang selesai dan bagaimana hasilnya, lalu Anda membaca generasi itu dengan kunci Anda untuk mendapatkan aset, tagihan, dan pesan error-nya.
Mendaftarkan endpoint
POST /v1/direct/webhooks membutuhkan cakupan 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"
}'| Field | Aturan |
|---|---|
url | HTTPS pada host publik (bukan alamat IP langsung, bukan alamat privat atau lokal), hingga 2.048 karakter |
events | satu atau beberapa jenis event |
description | opsional, hingga 200 karakter |
Responsnya adalah 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_secrethanya ditampilkan dalam respons ini. Simpan seperti Anda menyimpan kunci API.- Untuk merotasi rahasia, daftarkan endpoint baru, alihkan panggilan Anda ke id-nya, lalu hapus endpoint lama.
- Sebuah organisasi dapat memiliki hingga 10 endpoint.
Mengelola endpoint
| Permintaan | Cakupan | Fungsi |
|---|---|---|
GET /v1/direct/webhooks | assets:read | menampilkan daftar endpoint sebagai { "webhooks": [ … ] }, tidak pernah beserta rahasianya |
DELETE /v1/direct/webhooks/{webhook_id} | generations:write | menghapus endpoint; pengiriman yang masih tertunda ke endpoint itu dibatalkan |
Menautkan endpoint ke panggilan
Teruskan webhook_id di body panggilan alat. Setiap generasi yang dimulai oleh panggilan itu dikirim ke endpoint tersebut ketika mencapai status akhir yang dilanggani endpoint. Panggilan tanpa webhook_id tidak mengirim webhook.
Alat yang merender video di server Morphic (video_compose, transformasi video_*, dan burn_subtitles) belum menerima webhook_id; lakukan polling pada generasinya.
Jenis event
| Event | Dikirim saat |
|---|---|
generation.succeeded | generasi selesai dengan keluaran |
generation.failed | generasi gagal; tagihannya dikembalikan |
generation.cancelled | generasi dibatalkan; tagihannya dikembalikan |
- Setiap generasi menghasilkan paling banyak satu event.
queueddanin_progresstidak dikirim; lakukan polling jika Anda membutuhkannya.- Sebuah generasi dipantau selama 72 jam setelah dimulai. Generasi yang berakhir lebih lambat tidak mengirim event, jadi bacalah secara langsung.
Pengiriman
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 hanya membawa field berikut:
| Field | Arti |
|---|---|
object, id, tool, status, completed_at, metadata | seperti pada objek generasi |
error_code | null, atau kode dari generasi yang failed |
Event tidak pernah membawa keluaran, link, tagihan, model, atau pesan error, sehingga pengiriman yang salah alamat atau tercatat di log tidak membocorkan apa pun. Saat menerimanya, baca generasi itu dengan kunci Anda: GET /v1/direct/generations/{id}, atau pembacaan batch untuk beberapa generasi. Saat event dikirim, tidak ada lagi perubahan tagihan yang tertunda, jadi pembacaan itu sudah final.
| Header | Arti |
|---|---|
Morphic-Event-Id | id event, sama di setiap pengulangan; lakukan deduplikasi berdasarkan ini |
Morphic-Delivery-Id | percobaan yang satu ini; berbeda di setiap pengulangan |
Morphic-Event-Type | type dari body |
Morphic-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
Event biasanya dikirim dalam waktu sekitar satu menit setelah generasi mencapai status akhirnya. Ini bukan stream waktu nyata: untuk latensi terendah pada satu generasi yang sedang Anda tunggu, lakukan long-poll.
Memverifikasi tanda tangan
v1 adalah HMAC-SHA256 dalam heksadesimal, dengan signing_secret endpoint Anda sebagai kuncinya, atas string {t}.{raw request body}.
- Pisahkan header pada
,menjaditdanv1. - Hitung
HMAC_SHA256(secret, t + "." + raw_body)atas byte mentah yang Anda terima, sebelum parsing JSON atau serialisasi ulang apa pun. - Bandingkan hasilnya dengan
v1dalam waktu konstan. - Tolak pengiriman jika
tberselisih lebih dari 5 menit dari sekarang, untuk mencegah pemutaran ulang.
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);
});Endpoint yang tidak diverifikasi adalah pintu terbuka: siapa pun yang mengetahui URL-nya dapat memberi tahu Anda bahwa sebuah generasi telah selesai. Verifikasi setiap tanda tangan dan tolak stempel waktu yang lebih dari 5 menit.
Menjawab dan pengulangan
- Jawab dengan
2xxapa pun dalam 10 detik, lalu kerjakan prosesnya. - Selain itu dianggap percobaan gagal: status non-
2xx, timeout, koneksi ditolak, error TLS. - Pengalihan tidak diikuti;
3xxdianggap percobaan gagal. - Urutan tidak dijamin dan sebuah event dapat tiba lebih dari sekali. Buat handler Anda idempoten berdasarkan
Morphic-Event-Id, atau berdasarkandata.generation.id, karena satu generasi memiliki paling banyak satu event.
Percobaan yang gagal diulang setelah:
| Pengulangan | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| Jeda setelah percobaan sebelumnya | 1 menit | 5 menit | 15 menit | 1 jam | 3 jam | 6 jam | 12 jam |
Setelah pengulangan ke-7, sekitar 22 jam setelah percobaan pertama, event dibatalkan. Generasinya sendiri tidak terpengaruh: baca dengan GET /v1/direct/generations/{id}.
Log pengiriman
GET /v1/direct/webhooks/{webhook_id}/events (cakupan assets:read) mengembalikan 20 event terbaru untuk endpoint tersebut, masing-masing dengan body persis yang dikirim dan hasil setiap percobaan. Tambahkan ?generation_id=… untuk event dari satu generasi.
{
"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 event | Arti |
|---|---|
pending | belum terkirim; percobaan berikutnya mungkin masih menyusul |
delivered | endpoint Anda menjawab 2xx |
abandoned | pengulangan terakhir gagal, atau endpoint telah dihapus |
skipped | endpoint tidak melanggani jenis event tersebut |
Webhook adalah sinyal yang lebih hemat dan lebih cepat, bukan jaminan. Tetap lakukan polling sesekali pada generasi yang belum Anda dengar kabarnya sebagai jaring pengaman.
Jika Anda mengalami kendala atau memiliki pertanyaan, jangan ragu untuk menghubungi kami. Kami dengan senang hati akan membantu. Tulis kepada kami di support@morphic.com.
Generasi
Pantau generasi Direct API hingga status akhirnya dengan long-polling, baca beberapa sekaligus, dan ketahui kapan harus melakukan polling.
Kredit dan pemakaian
Cara panggilan Direct API ditagih, diselesaikan, dan dikembalikan kreditnya, cara meminta penawaran harga sebuah pekerjaan terlebih dahulu, serta cara membaca pemakaian dan buku besar kunci Anda.