Documentação

Webhooks

Receba um aviso no seu servidor a cada mudança de status de uma correspondência ou verificação.

Um webhook é uma URL do seu servidor que a CartaFlow chama quando algo acontece na sua conta. A cada mudança de status de uma correspondência ou de uma verificação, enviamos um POST com o evento no corpo. Assim o seu sistema fica sabendo que uma correspondência foi postada, ou que um endereço foi verificado, sem consultar a API de tempos em tempos.

Configurar

Crie um endpoint no seu servidor que aceite POST com corpo JSON e responda rápido. A URL precisa usar HTTPS.

Cadastre a URL no painel, em Desenvolvedores > Webhooks, e escolha os eventos que quer receber.

Copie o segredo de assinatura. Cada webhook tem um segredo que começa com whsec_, mostrado no painel. Guarde em uma variável de ambiente, como CARTAFLOW_WEBHOOK_SECRET, e use para conferir a assinatura de cada entrega.

O que chega no seu servidor

O corpo é um objeto event. Em data vem o objeto inteiro, como estava logo depois do acontecimento, então você não precisa consultar a API depois:

Corpo de um evento letter.posted
{
  "id": "evt_6Tq1Yz8Wm3Rb",
  "object": "event",
  "type": "letter.posted",
  "data": {
    "id": "ltr_8Kq2wX4mN7pR",
    "object": "letter",
    "status": "posted",
    "to": {
      "name": "Destinatário Exemplo",
      "street": "Rua Exemplo",
      "number": "128",
      "complement": "Ap. 52",
      "neighborhood": "Centro",
      "city": "São Paulo",
      "state": "SP",
      "postal_code": "01001-000"
    },
    "reference": "fatura-2026-10-0042",
    "metadata": { "customer_id": "1842" },
    "status_transitions": {
      "received_at": "2026-10-13T14:20:00Z",
      "in_production_at": "2026-10-13T21:00:00Z",
      "printed_at": "2026-10-14T10:42:00Z",
      "posted_at": "2026-10-14T16:05:00Z",
      "canceled_at": null,
      "failed_at": null
    },
    "created_at": "2026-10-13T14:20:00Z"
  },
  "created_at": "2026-10-14T16:05:00Z"
}

Para caber na página, o exemplo mostra só alguns campos de data. Na entrega real, data traz a correspondência completa, igual à resposta de GET /v1/letters/{letter_id}.

Cada entrega vem com três cabeçalhos:

CabeçalhoO que é
webhook-idO id do evento, igual a id do corpo. É o mesmo em todas as tentativas de entrega do mesmo evento.
webhook-timestampO momento do envio, em segundos Unix.
webhook-signatureA assinatura do corpo, no formato v1,<assinatura>. Pode trazer mais de uma, separadas por espaço, durante a troca de um segredo.

Conferir a assinatura

Confira a assinatura antes de confiar no conteúdo. Ela prova que a entrega veio da CartaFlow e que o corpo não foi alterado. A CartaFlow segue a especificação Standard Webhooks, que tem bibliotecas oficiais para várias linguagens.

Use o corpo cru, exatamente como chegou. Se o seu framework converter o JSON e você gerar o texto de novo, a assinatura não confere.

// npm install standardwebhooks express
import express from 'express';
import { Webhook } from 'standardwebhooks';

const app = express();
const webhook = new Webhook(process.env.CARTAFLOW_WEBHOOK_SECRET);

// express.raw mantém o corpo exatamente como chegou.
app.post('/webhooks/cartaflow', express.raw({ type: 'application/json' }), (req, res) => {
  let event;
  try {
    event = webhook.verify(req.body, req.headers);
  } catch {
    return res.status(400).send('Assinatura inválida');
  }

  res.status(200).end(); // responda primeiro
  queue.add(event); // processe depois, fora da requisição
});

Responda rápido e processe depois

Responda com qualquer status 2xx em até 15 segundos. Esse é o sinal de que você recebeu o evento. Faça o trabalho demorado, como atualizar o cadastro ou mandar um e-mail, depois de responder, por exemplo em uma fila.

Qualquer outra resposta, ou nenhuma resposta a tempo, faz a CartaFlow tentar de novo:

TentativaQuando
1Na hora do evento
25 segundos depois da anterior
35 minutos depois
430 minutos depois
52 horas depois
65 horas depois
710 horas depois
810 horas depois

Depois da última tentativa, o evento não é enviado de novo. Ele continua disponível em GET /v1/events por 30 dias.

Repetições e ordem

  • O mesmo evento pode chegar mais de uma vez. Uma entrega pode ser repetida mesmo que o seu servidor tenha recebido, por exemplo se a resposta se perder no caminho. Guarde o webhook-id dos eventos processados e ignore os repetidos.
  • Os eventos podem chegar fora de ordem. Um letter.printed pode chegar depois de um letter.posted. Não deduza o status pela ordem de chegada: use o status e o status_transitions do objeto em data, que são uma foto do momento do evento. Para ter certeza do estado atual, consulte o objeto pela API.

Recuperar eventos perdidos

Se o seu servidor ficou fora do ar, busque o que perdeu em GET /v1/events, filtrando por created_after. Para ver a história de uma correspondência, use object_id. Os eventos ficam guardados por 30 dias e são os mesmos que os webhooks entregam.

Evento de teste

No painel, em Desenvolvedores > Webhooks, o botão Enviar evento de teste envia para o seu endpoint uma entrega do tipo webhook.test. Use para conferir que a URL responde, que a assinatura confere e que o seu servidor responde 2xx a tempo.

  • A entrega tem os mesmos cabeçalhos e a mesma assinatura das outras, com o segredo whsec_ do webhook.
  • O corpo segue o formato de qualquer evento, com type: "webhook.test" e um objeto de exemplo em data. Esse objeto não existe na sua conta: não grave nada a partir dele.
  • O evento de teste é enviado uma vez, sem novas tentativas, e nunca aparece em GET /v1/events.

Durante o desenvolvimento, a CartaFlow precisa alcançar a sua URL pela internet. Use um túnel, como ngrok ou Cloudflare Tunnel, para expor o seu servidor local com uma URL HTTPS, cadastre essa URL no painel e envie um evento de teste.

Eventos

Cada mudança de status gera um evento com o nome objeto.novo_status. Quando uma correspondência é alterada no painel antes da produção, sem mudar de status (a data de envio ou o endereço, por exemplo), o evento é letter.updated, com a correspondência como ficou.

EventoQuando é enviado
letter.scheduledUma correspondência foi agendada com send_date. Ainda não foi cobrada.
letter.receivedUma correspondência foi cobrada e entrou na fila de produção: logo depois de criada ou, se foi agendada, na data do envio. Vale para correspondências criadas pela API e pelo painel.
letter.in_productionA correspondência entrou em um lote de impressão e não pode mais ser cancelada.
letter.printedA correspondência foi impressa e envelopada.
letter.postedA correspondência foi entregue aos Correios. É o último evento de uma correspondência enviada.
letter.canceledA correspondência foi cancelada. Veja cancellation_reason: requested quando você cancelou, insufficient_balance quando uma correspondência agendada não pôde ser cobrada na data.
letter.failedA correspondência falhou na produção e não será postada. O valor voltou para o saldo automaticamente. Veja failure_reason.
letter.updatedA correspondência foi alterada no painel antes da produção, sem mudar de status: data de envio, endereço, arquivo, variáveis, impressão, serviços dos Correios ou referência. data traz a correspondência como ficou. Se a mudança alterou o preço de uma correspondência agendada, price traz o novo valor.
verification.receivedUma verificação foi criada, pela API ou pelo painel (veja source), e a correspondência com o código está na fila de produção.
verification.in_productionA correspondência com o código está sendo impressa. A partir daqui, cancelar revoga a verificação, sem devolução.
verification.awaiting_codeA correspondência com o código foi postada. A pessoa já pode confirmar quando receber.
verification.verifiedA pessoa confirmou o código certo. O endereço está verificado.
verification.failedForam digitados 5 códigos errados e a verificação foi bloqueada.
verification.expiredA pessoa não confirmou o código em 60 dias desde a postagem.
verification.canceledA verificação foi cancelada antes da postagem, por você ou pela CartaFlow, e o valor voltou para o saldo.
verification.revokedVocê cancelou a verificação depois que a produção começou. O código deixou de funcionar e o valor não volta para o saldo. Se ela estava verified, trate o endereço como não verificado.

Trate tipos desconhecidos sem erro

Responda 2xx a qualquer entrega com assinatura válida, mesmo de um tipo que o seu sistema não usa, como webhook.test, e ignore o que você não conhece. Novos tipos de evento podem surgir sem aviso. Veja Versões e compatibilidade.

Nesta página