Webhooks
Erhalten Sie eine signierte Benachrichtigung, wenn eine Generierung der Direct API abgeschlossen ist, prüfen Sie sie und lesen Sie die Generierung für die Details.
Ein Webhook ist ein HTTPS-Endpunkt von Ihnen, den Morphic aufruft, wenn eine Generierung einen endgültigen Status erreicht. Zustellungen werden signiert, etwa einen Tag lang wiederholt und protokolliert. Jedes Ereignis ist eine schlanke Benachrichtigung: Es sagt, welche Generierung wie abgeschlossen wurde, und Sie lesen die Generierung mit Ihrem Schlüssel, um ihre Assets, ihre Abrechnung und ihre Fehlermeldung zu erhalten.
Einen Endpunkt registrieren
POST /v1/direct/webhooks benötigt die Berechtigung 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"
}'| Feld | Regeln |
|---|---|
url | HTTPS auf einem öffentlichen Host (keine IP-Literale, keine privaten oder lokalen Adressen), bis zu 2048 Zeichen |
events | ein oder mehrere Ereignistypen |
description | optional, bis zu 200 Zeichen |
Die Antwort ist 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_secretwird nur in dieser Antwort angezeigt. Bewahren Sie es so sicher auf wie den API-Schlüssel.- Um das Secret zu rotieren, registrieren Sie einen neuen Endpunkt, stellen Ihre Aufrufe auf dessen ID um und löschen dann den alten.
- Eine Organisation kann bis zu 10 Endpunkte haben.
Endpunkte verwalten
| Anfrage | Berechtigung | Funktion |
|---|---|---|
GET /v1/direct/webhooks | assets:read | listet Endpunkte als { "webhooks": [ … ] } auf, nie mit ihren Secrets |
DELETE /v1/direct/webhooks/{webhook_id} | generations:write | entfernt den Endpunkt; noch ausstehende Zustellungen an ihn werden verworfen |
Einen Endpunkt an einen Aufruf anhängen
Übergeben Sie webhook_id im Body des Tool-Aufrufs. Jede Generierung, die dieser Aufruf startet, wird an diesen Endpunkt zugestellt, sobald sie einen endgültigen Status erreicht, den der Endpunkt abonniert hat. Aufrufe ohne webhook_id senden keine Webhooks.
Die Tools, die Videos auf den Servern von Morphic rendern (video_compose, die video_*-Transformationen und burn_subtitles), akzeptieren webhook_id noch nicht; fragen Sie ihre Generierungen per Polling ab.
Ereignistypen
| Ereignis | Gesendet, wenn |
|---|---|
generation.succeeded | die Generierung mit einer Ausgabe abgeschlossen wurde |
generation.failed | die Generierung fehlgeschlagen ist; ihre Belastung wird erstattet |
generation.cancelled | die Generierung abgebrochen wurde; ihre Belastung wird erstattet |
- Jede Generierung erzeugt höchstens ein Ereignis.
queuedundin_progresswerden nicht zugestellt; fragen Sie sie per Polling ab, wenn Sie sie benötigen.- Eine Generierung wird ab ihrem Start 72 Stunden lang beobachtet. Eine, die später endet, sendet kein Ereignis, lesen Sie sie also stattdessen.
Die Zustellung
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 enthält nur diese Felder:
| Feld | Bedeutung |
|---|---|
object, id, tool, status, completed_at, metadata | wie im Generierungsobjekt |
error_code | null oder der Code einer failed-Generierung |
Ein Ereignis enthält nie Ausgaben, Links, Abrechnung, das Modell oder die Fehlermeldung, sodass eine Zustellung, die am falschen Ort oder in einem Log landet, nichts preisgibt. Lesen Sie die Generierung nach dem Empfang mit Ihrem Schlüssel: GET /v1/direct/generations/{id} oder für mehrere das gebündelte Lesen. Wenn ein Ereignis gesendet wird, steht an seiner Abrechnung nichts mehr aus, dieses Lesen ist also endgültig.
| Header | Bedeutung |
|---|---|
Morphic-Event-Id | die ID des Ereignisses, bei jeder Wiederholung identisch; deduplizieren Sie anhand dieser ID |
Morphic-Delivery-Id | dieser eine Zustellversuch; bei jeder Wiederholung anders |
Morphic-Event-Type | der type des Bodys |
Morphic-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
Ein Ereignis wird in der Regel innerhalb von etwa einer Minute gesendet, nachdem die Generierung ihren endgültigen Status erreicht hat. Es ist kein Echtzeit-Stream: Für die geringste Latenz bei einer Generierung, auf die Sie gerade warten, fragen Sie sie per Long-Polling ab.
Die Signatur prüfen
v1 ist der hexadezimale HMAC-SHA256, mit dem signing_secret Ihres Endpunkts als Schlüssel, über den String {t}.{raw request body}.
- Teilen Sie den Header an
,intundv1auf. - Berechnen Sie
HMAC_SHA256(secret, t + "." + raw_body)über die empfangenen Rohbytes, vor jedem JSON-Parsing oder jeder erneuten Serialisierung. - Vergleichen Sie das Ergebnis in konstanter Zeit mit
v1. - Weisen Sie die Zustellung zurück, wenn
tmehr als 5 Minuten von der aktuellen Zeit abweicht, um Replay-Angriffe zu verhindern.
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);
});Ein ungeprüfter Endpunkt ist eine offene Tür: Jeder, der seine URL kennt, kann Ihnen melden, dass eine Generierung abgeschlossen ist. Prüfen Sie jede Signatur und weisen Sie einen Zeitstempel zurück, der älter als 5 Minuten ist.
Antworten und Wiederholungen
- Antworten Sie innerhalb von 10 Sekunden mit einem beliebigen
2xxund erledigen Sie die Arbeit danach. - Alles andere ist ein fehlgeschlagener Versuch: ein Status außer
2xx, ein Timeout, eine abgelehnte Verbindung, ein TLS-Fehler. - Weiterleitungen werden nicht verfolgt; ein
3xxist ein fehlgeschlagener Versuch. - Die Reihenfolge ist nicht garantiert, und ein Ereignis kann mehrfach ankommen. Machen Sie Ihren Handler idempotent bezüglich
Morphic-Event-Idoderdata.generation.id, da eine Generierung höchstens ein Ereignis hat.
Ein fehlgeschlagener Versuch wird wiederholt nach:
| Wiederholung | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| Wartezeit nach dem vorherigen Versuch | 1 min | 5 min | 15 min | 1 h | 3 h | 6 h | 12 h |
Nach der 7. Wiederholung, etwa 22 Stunden nach dem ersten Versuch, wird das Ereignis verworfen. Die Generierung selbst ist davon nicht betroffen: Lesen Sie sie mit GET /v1/direct/generations/{id}.
Zustellprotokoll
GET /v1/direct/webhooks/{webhook_id}/events (Berechtigung assets:read) liefert die letzten 20 Ereignisse des Endpunkts, jeweils mit dem exakt gesendeten Body und dem Ergebnis jedes Versuchs. Hängen Sie ?generation_id=… an, um die Ereignisse einer einzelnen Generierung zu erhalten.
{
"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 }
]
}
]
}Ereignis-status | Bedeutung |
|---|---|
pending | noch nicht zugestellt; weitere Versuche können folgen |
delivered | Ihr Endpunkt hat mit 2xx geantwortet |
abandoned | die letzte Wiederholung ist fehlgeschlagen, oder der Endpunkt wurde entfernt |
skipped | der Endpunkt hat diesen Ereignistyp nicht abonniert |
Webhooks sind das günstigere und schnellere Signal, keine Garantie. Fragen Sie Generierungen, von denen Sie nichts gehört haben, gelegentlich als Sicherheitsnetz ab.
Wenn Sie Probleme haben oder Fragen haben, können Sie sich gerne an uns wenden. Wir helfen Ihnen gerne. Schreiben Sie uns an support@morphic.com.
Generierungen
Verfolgen Sie eine Generierung der Direct API per Long-Polling bis zu ihrem endgültigen Status, lesen Sie mehrere auf einmal und erfahren Sie, wann Sie abfragen sollten.
Credits und Nutzung
Wie Aufrufe der Direct API berechnet, abgerechnet und erstattet werden, wie Sie einen Auftrag vorab kalkulieren und wie Sie die Ausgaben und das Buchungsprotokoll Ihres Schlüssels lesen.