Webhooks

Receba um aviso assinado quando uma geração da Direct API terminar, verifique-o e leia a geração para obter os detalhes.

Um webhook é um endpoint HTTPS seu que o Morphic chama quando uma geração chega a um status final. As entregas são assinadas, repetidas por cerca de um dia e registradas. Cada evento é um aviso enxuto: ele diz qual geração terminou e como, e você lê a geração com a sua chave para obter os recursos, a cobrança e a mensagem de erro.

Registrar um endpoint

POST /v1/direct/webhooks exige o escopo 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"
      }'
CampoRegras
urlHTTPS em um host público (sem IPs literais, sem endereços privados ou locais), até 2.048 caracteres
eventsum ou mais tipos de evento
descriptionopcional, até 200 caracteres

A resposta é 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 aparece apenas nesta resposta. Guarde-o como você guarda a chave de API.
  • Para rotacionar o segredo, registre um novo endpoint, passe a usar o ID dele nas suas chamadas e depois exclua o antigo.
  • Uma organização pode ter até 10 endpoints.

Gerenciar endpoints

SolicitaçãoEscopoO que faz
GET /v1/direct/webhooksassets:readlista os endpoints como { "webhooks": [ … ] }, nunca com seus segredos
DELETE /v1/direct/webhooks/{webhook_id}generations:writeremove o endpoint; as entregas ainda pendentes para ele são abandonadas

Associar um endpoint a uma chamada

Passe webhook_id no corpo da chamada da ferramenta. Cada geração que essa chamada iniciar é entregue a esse endpoint quando chegar a um status final ao qual o endpoint se inscreveu. Chamadas sem webhook_id não enviam webhooks.

As ferramentas que renderizam vídeo nos servidores da Morphic (video_compose, as transformações video_* e burn_subtitles) ainda não aceitam webhook_id; consulte as gerações delas por polling.

Tipos de evento

EventoEnviado quando
generation.succeededa geração terminou com um resultado
generation.faileda geração falhou; a cobrança é reembolsada
generation.cancelleda geração foi cancelada; a cobrança é reembolsada
  • Cada geração produz no máximo um evento.
  • queued e in_progress não são entregues; consulte por polling se precisar deles.
  • Uma geração é acompanhada por 72 horas após o início. Uma que termine depois disso não envia evento, então leia-a diretamente.

A entrega

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 traz apenas estes campos:

CampoSignificado
object, id, tool, status, completed_at, metadatacomo no objeto de geração
error_codenull, ou o código de uma geração failed

Um evento nunca traz resultados, links, cobrança, o modelo ou a mensagem de erro, então uma entrega que chegue ao lugar errado ou acabe em um log não revela nada. Ao recebê-la, leia a geração com a sua chave: GET /v1/direct/generations/{id}, ou a leitura em lote para várias. Quando um evento é enviado, não há mais nada pendente na cobrança dele, então essa leitura é final.

CabeçalhoSignificado
Morphic-Event-Ido ID do evento, idêntico em todas as novas tentativas; elimine duplicatas por ele
Morphic-Delivery-Idesta tentativa específica; muda a cada nova tentativa
Morphic-Event-Typeo type do corpo
Morphic-Signaturet=<unix seconds>,v1=<hex HMAC-SHA256>

Um evento costuma ser enviado em cerca de um minuto depois que a geração chega ao status final. Não é um stream em tempo real: para a menor latência em uma geração que você está aguardando, faça long-poll dela.

Verificar a assinatura

v1 é o HMAC-SHA256 em hexadecimal, com o signing_secret do seu endpoint como chave, da string {t}.{raw request body}.

  1. Divida o cabeçalho em , para obter t e v1.
  2. Calcule HMAC_SHA256(secret, t + "." + raw_body) sobre os bytes brutos que você recebeu, antes de qualquer parsing ou reserialização de JSON.
  3. Compare-o com v1 em tempo constante.
  4. Rejeite a entrega se t estiver a mais de 5 minutos do horário atual, para impedir reenvios maliciosos.
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);
});

Um endpoint sem verificação é uma porta aberta: qualquer pessoa que descubra a URL dele pode dizer que uma geração terminou. Verifique todas as assinaturas e rejeite carimbos de tempo com mais de 5 minutos.

Resposta e novas tentativas

  • Responda com qualquer 2xx em até 10 segundos e só depois faça o trabalho.
  • Qualquer outra coisa é uma tentativa com falha: um status diferente de 2xx, um timeout, uma conexão recusada, um erro de TLS.
  • Redirecionamentos não são seguidos; um 3xx é uma tentativa com falha.
  • A ordem não é garantida e um evento pode chegar mais de uma vez. Torne o seu handler idempotente em relação a Morphic-Event-Id, ou a data.generation.id, já que uma geração tem no máximo um evento.

Uma tentativa com falha é repetida depois de:

Nova tentativa1234567
Espera após a tentativa anterior1 min5 min15 min1 h3 h6 h12 h

Depois da 7ª nova tentativa, cerca de 22 horas após a primeira, o evento é abandonado. A geração em si não é afetada: leia-a com GET /v1/direct/generations/{id}.

Registro de entregas

GET /v1/direct/webhooks/{webhook_id}/events (escopo assets:read) retorna os 20 eventos mais recentes do endpoint, cada um com o corpo exato enviado e o resultado de cada tentativa. Adicione ?generation_id=… para ver os eventos de uma geração.

{
  "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 do eventoSignificado
pendingainda não entregue; mais tentativas podem ocorrer
deliveredo seu endpoint respondeu 2xx
abandoneda última tentativa falhou, ou o endpoint foi removido
skippedo endpoint não se inscreveu nesse tipo de evento

Webhooks são o sinal mais barato e mais rápido, não uma garantia. Mantenha uma consulta ocasional das gerações das quais você não teve notícia como rede de segurança.


Se você tiver algum problema ou alguma dúvida, entre em contato. Teremos prazer em ajudar. Escreva para nós em support@morphic.com.

Nesta página