Webhooks
Receba um aviso quando uma execução terminar, em vez de ficar consultando.
Registre um endpoint uma vez e depois passe seu webhook_id quando você inicia uma execução, e nós o chamamos quando essa execução muda para um estado ao qual você se inscreveu — geralmente em um minuto.
Registrar um endpoint
POST {base_url}/webhooks
{
"url": "https://hooks.example.com/morphic",
"events": ["workflow_run.succeeded", "workflow_run.failed"],
"description": "pipeline de história"
}Requer runs:write. A URL deve ser pública https sem credenciais nela; uma organização mantém até 10 endpoints.
A 201 resposta carrega o id — passe-o como webhook_id em uma execução — e seu segredo de assinatura (whsec_…), mostrado uma única vez. Armazene-o como faria com a chave da API.
GET {base_url}/webhooks
DELETE {base_url}/webhooks/{webhook_id}GET (runs:read) lista seus endpoints, nunca seus segredos. DELETE (runs:write) remove um; as entregas ainda pendentes para ele são descartadas. Para rotacionar um segredo, registre um novo endpoint e mova suas execuções para ele.
Eventos
| Evento | Dispara quando |
|---|---|
workflow_run.succeeded | a execução terminou; seus ativos estão prontos |
workflow_run.failed | a execução parou; erro explica por quê |
workflow_run.needs_input | a execução está aguardando uma pessoa no Morphic Studio |
workflow_run.expired | a execução nunca terminou durante sua vida útil |
A entrega
POST https://hooks.example.com/morphic
Morphic-Event-Id: 0192f4a0-3c71-7b92-8e14-5d6f2a9b3c07
Morphic-Delivery-Id: 0192f4a0-4d82-7c03-9f25-6e7a3b0c4d18
Morphic-Event-Type: workflow_run.succeeded
Morphic-Signature: t=1790056632,v1=3f9c1a…
{
"id": "0192f4a0-3c71-7b92-8e14-5d6f2a9b3c07",
"type": "workflow_run.succeeded",
"created_at": "2026-09-22T04:17:12Z",
"api_version": "v1",
"data": {
"run": { "id": "0192f3d0-…", "status": "succeeded", "assets": [], "credits_used": 1792 }
}
}A execução tem a mesma estrutura Ler uma execução de workflow retorna, ativos incluídos — então uma entrega bem-sucedida não precisa de uma chamada de acompanhamento. É a execução como estava quando o evento foi disparado, e os links dos ativos permanecem válidos por cerca de um dia, desde que as retentativas de entrega continuem.
Verifique cada entrega
Calcule um HMAC-SHA256 de {timestamp}.{raw body} com seu segredo de assinatura e compare-o com v1 em tempo constante. Use o corpo bruto, antes de qualquer análise JSON.
import crypto from 'node:crypto';
function verify({ rawBody, header, secret }) {
const parts = Object.fromEntries(
header.split(',').map((pair) => pair.split('=')),
);
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
const signed = Buffer.from(expected);
const given = Buffer.from(parts.v1);
if (signed.length !== given.length) return false;
if (!crypto.timingSafeEqual(signed, given)) return false;
// Recuse uma entrega reenviada.
return Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
}Um endpoint de webhook não verificado é uma porta aberta: qualquer pessoa que descubra a URL pode informar que uma execução foi bem-sucedida. Verifique a assinatura e rejeite um timestamp com mais de cinco minutos.
Retentativas e ordenação
- Responda
2xxem 10 segundos. Reconheça primeiro e depois faça o trabalho — um handler lento é interpretado como falha. - Uma resposta não-
2xxou um timeout é tentado novamente com backoff exponencial por cerca de um dia, depois é descartado. Um redirecionamento não é seguido e conta como uma falha. - Somente os eventos aos quais um endpoint se inscreveu são enviados; uma execução que chega a outro estado não informa nada sobre isso.
- As entregas podem chegar fora de ordem e mais de uma vez. Use como chave
Morphic-Event-Ide ignore uma que você já tratou. - Uma
bem-sucedidaentrega pode chegar antes de o seu próprio registro da execução existir. Lide com isso em vez de gerar erro — ou recorra a polling para essas execuções.
Webhooks são uma otimização, não uma garantia. Mantenha uma varredura lenta que consulte execuções das quais você não tenha ouvido falar, para que um deploy ruim do seu lado não faça você perder a saída de um dia.