Pular para o conteúdo
Docs

Referência

O formato exato das requisições de webhook do Emailit, do método e dos cabeçalhos ao array JSON de eventos, além de ordenação, duplicatas e como responder.

Atualizado em 1 de out. de 2026

Esta página descreve o que chega ao seu endpoint: a requisição HTTP, os cabeçalhos, o corpo JSON e o que o Emailit espera como resposta. Use-a ao escrever ou depurar um handler de webhook.

Requisição

Propriedade Valor
Método POST
Corpo Um array JSON de 1 a 100 eventos, compacto (sem espaços extras)
Timeout 30 segundos
Redirecionamentos Não são seguidos. Uma resposta 3xx conta como falha.
Concorrência Uma requisição por vez por webhook. Os lotes são enviados um após o outro.
Latência O Emailit verifica se há eventos novos a cada poucos segundos, então a maioria dos eventos chega em segundos.
HTTP
POST /webhooks/emailit HTTP/1.1
Host: acme.com
Content-Type: application/json
User-Agent: Emailit-Webhooks/2.0
X-Emailit-Signature: 7242b580f77ec488f8ac21b57f092e3db61a431694f13074c7b4c85a4dd04be3
X-Emailit-Timestamp: 1790846045

Cabeçalhos

Cabeçalho Descrição
Content-Type Sempre application/json.
User-Agent Sempre Emailit-Webhooks/2.0.
X-Emailit-Signature HMAC-SHA256 em hexadecimal de {timestamp}.{raw body}, calculado com o segredo completo do webhook (incluindo whsec_). Consulte Assinatura da requisição.
X-Emailit-Timestamp Timestamp Unix, em segundos, do momento em que o Emailit assinou a requisição. Cada tentativa, incluindo as novas tentativas, é assinada de novo com um timestamp novo.

Corpo

O corpo é sempre um array JSON, mesmo quando contém um único evento. Cada elemento tem este formato:

Campo Tipo Descrição
event_id string O ID do evento, que começa com evt_. O mesmo evento mantém o mesmo ID em todas as novas tentativas. Eventos de teste começam com evt_test_.
type string O tipo de evento, como email.delivered.
object objeto O recurso a que o evento se refere.
data objeto Contém object de novo. data.object e o object de nível superior são idênticos; leia o que preferir.

Os campos dentro de object dependem do tipo. Eventos de status de e-mail descrevem o e-mail; email.clicked e email.loaded descrevem o clique ou o carregamento e trazem o e-mail aninhado; eventos de recursos, como contact.created, descrevem o recurso.

Exemplo de lote

Esta requisição traz dois eventos: uma entrega e, depois, um clique em um link do mesmo e-mail.

JSON
[
  {
    "event_id": "evt_2xGk7Nq1VbD5sR8tLmW3eYhC6aP",
    "type": "email.delivered",
    "object": {
      "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
      "object": "email",
      "from": "billing@acme.com",
      "to": "ada@example.com",
      "subject": "Your receipt #1042",
      "status": "delivered",
      "meta": { "order_id": "1042" },
      "updated_at": "2026-10-01T09:14:03.512000+00:00",
      "created_at": "2026-10-01T09:14:01.207000+00:00"
    },
    "data": {
      "object": {
        "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
        "object": "email",
        "from": "billing@acme.com",
        "to": "ada@example.com",
        "subject": "Your receipt #1042",
        "status": "delivered",
        "meta": { "order_id": "1042" },
        "updated_at": "2026-10-01T09:14:03.512000+00:00",
        "created_at": "2026-10-01T09:14:01.207000+00:00"
      }
    }
  },
  {
    "event_id": "evt_2xGkC8w2TnF4yR7bMqL1sVdJ6pE",
    "type": "email.clicked",
    "object": {
      "id": "click_2xGkC7v5PmD3xQ9aLnK2rUcH8oW",
      "object": "click",
      "email_id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
      "email": {
        "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
        "rcpt_to": "ada@example.com",
        "mail_from": "billing@acme.com",
        "subject": "Your receipt #1042",
        "created_at": "2026-10-01T09:14:01.207000+00:00",
        "campaign": null,
        "meta": { "order_id": "1042" }
      },
      "link": {
        "id": "link_2xGk7Mb6QwE1zS8cNpT4vXfK3gB",
        "url": "https://acme.com/orders/1042"
      },
      "contact": { "id": "con_2xFh3Ka9LmP2nR6tVwB8cDqY5sZ", "email": "ada@example.com" },
      "ip_address": "203.0.113.24",
      "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
      "created_at": "2026-10-01T09:20:47.884000+00:00"
    },
    "data": {
      "object": {
        "id": "click_2xGkC7v5PmD3xQ9aLnK2rUcH8oW",
        "object": "click",
        "email_id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
        "email": {
          "id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
          "rcpt_to": "ada@example.com",
          "mail_from": "billing@acme.com",
          "subject": "Your receipt #1042",
          "created_at": "2026-10-01T09:14:01.207000+00:00",
          "campaign": null,
          "meta": { "order_id": "1042" }
        },
        "link": {
          "id": "link_2xGk7Mb6QwE1zS8cNpT4vXfK3gB",
          "url": "https://acme.com/orders/1042"
        },
        "contact": { "id": "con_2xFh3Ka9LmP2nR6tVwB8cDqY5sZ", "email": "ada@example.com" },
        "ip_address": "203.0.113.24",
        "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
        "created_at": "2026-10-01T09:20:47.884000+00:00"
      }
    }
  }
]

Os timestamps estão em ISO 8601, em UTC. meta são os metadados que você anexou ao enviar, ou null. contact é null quando o destinatário não é um dos seus contatos, e campaign é null para e-mails enviados pela API e por SMTP.

Ordenação

Dentro de uma requisição, os eventos vêm do mais antigo para o mais recente. Entre requisições, não há garantia de ordem: um lote que falhou é reenviado mais tarde, quando eventos mais novos podem já ter chegado, e uma nova tentativa manual pode reenviar eventos antigos depois dos novos.

Não conte com a ordem de chegada. Para eventos de e-mail, use o status e o updated_at do e-mail e mantenha o estado mais avançado que você já viu (por exemplo, não sobrescreva clicked com um delivered atrasado). Na dúvida, busque o estado atual com Obter um e-mail.

Duplicatas

O mesmo evento pode chegar mais de uma vez:

  • Quando o seu endpoint dá timeout ou retorna um erro depois de processar parte de um lote, o lote inteiro é reenviado, incluindo os eventos que você já tratou.
  • Quando você usa Retry failed ou tenta de novo uma única requisição.

Guarde cada event_id processado, com uma restrição de unicidade, e ignore os eventos que você já viu.

Como responder

A sua resposta Resultado
Qualquer 2xx em até 30 segundos Todos os eventos do lote são marcados como Delivered. O corpo da resposta é ignorado.
3xx, 4xx ou 5xx O lote falhou e é reenviado.
Nenhuma resposta em 30 segundos, erro de conexão, erro de TLS O lote falhou e é reenviado. O painel mostra o código de status 0.

Nas requisições com falha, o Emailit guarda os primeiros 2.000 caracteres do corpo da sua resposta. Você pode lê-los na aba Requests do webhook, por isso vale a pena retornar uma mensagem de erro curta para facilitar a depuração.

Recomendações:

  • Verifique e confirme o recebimento rápido. Confira a assinatura, coloque os eventos em uma fila ou em uma tabela e retorne 200. Faça o trabalho demorado, como chamar outras APIs, em um job em segundo plano.
  • Retorne 2xx para os eventos que você ignora. Caso contrário, eles são reenviados por dias.
  • Retorne 401 ou 403 para uma assinatura inválida. A requisição é reenviada como qualquer falha, o que dá tempo para corrigir um segredo mal configurado.

Consulte Novas tentativas e falhas para ver o cronograma de novas tentativas e o que acontece quando um endpoint continua falhando.

Esta página foi útil?

Obrigado pelo feedback.

Obrigado, lemos todas as mensagens.