C C-Connect Documentação

Webhooks

Registar um endpoint, verificar a assinatura, e o que faz com que o desliguemos.

Em vez de perguntares periodicamente o que aconteceu, dizes-nos para onde empurrar. Cada evento sai num POST, assinado, com repetições.

Registar

No painel, em Webhooks, ou pela API:

curl -X POST https://app.c-connect.pt/v1/webhooks \
  -H "Authorization: Bearer $CCONNECT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://api.aempresa.pt/cconnect",
    "events": ["delivered", "bounced", "complained"]
  }'

Só https, e com certificado válido: a carga leva endereços de destinatários.

Sem events, enviamos todos. Um endpoint que não recebe nada é pior do que um que recebe a mais, por isso a omissão é generosa e não restritiva.

A resposta traz o segredo de assinatura, uma vez e só uma. Guarda-o.

Registar um endpoint e copiar o segredo de assinatura.

Verificar a assinatura

Cada entrega traz este cabeçalho:

X-CConnect-Signature: t=1758182462,v1=8f3c...9ab

O t é a hora em segundos. O v1 é um HMAC SHA-256, com o teu segredo, sobre a string "<t>.<corpo em bruto>".

O corpo em bruto, byte a byte como chegou. Se descodificares o JSON e voltares a codificá-lo, a assinatura deixa de bater, porque a ordem das chaves e os espaços mudam.

$timestamp = ...;   // o t do cabeçalho
$expected = hash_hmac('sha256', $timestamp.'.'.$rawBody, $secret);

if (! hash_equals($expected, $received)) {
    abort(400);
}

Usa sempre uma comparação de tempo constante, o hash_equals em PHP. Um === sobre strings devolve mais depressa quando os primeiros caracteres não batem, e isso chega para um atacante adivinhar a assinatura byte a byte.

Verifica também que o t é recente. Aceitamos cinco minutos de tolerância do nosso lado; faz o mesmo, e recusa uma entrega mais velha do que isso. É o que impede que alguém capture um pedido e o repita amanhã.

O que responder

200, e depressa. Se demorares mais de dez segundos consideramos a tentativa falhada.

O padrão que funciona é: verificar a assinatura, gravar o evento numa fila tua, responder 200, e processar depois. Um endpoint que faz trabalho pesado antes de responder acaba por parecer avariado num dia de volume.

Qualquer resposta fora dos 2xx conta como falha, incluindo um 301 para outro URL: não seguimos redireccionamentos, porque um redireccionamento é uma forma de enviar a carga para um sítio que não registaste.

As repetições

Sete tentativas, ao longo de cerca de 33 horas:

Tentativa Depois de
1 imediatamente
2 1 minuto
3 5 minutos
4 30 minutos
5 2 horas
6 6 horas
7 24 horas

Depois disso, aquela entrega é dada como falhada e não volta a ser tentada.

Quando desligamos um endpoint

Ao fim de dez falhas seguidas, desactivamos o endpoint. No painel aparece como Desactivado por falhas seguidas, e pela API o campo disabled_at fica preenchido.

É dito em vez de ficar em silêncio de propósito: um endpoint que deixou de receber sem ninguém saber é a razão pela qual alguém descobre um mês depois que perdeu os eventos todos.

Uma entrega com sucesso põe o contador a zero. Para voltar a ligar, o botão Reativar no painel, ou:

curl -X PATCH https://app.c-connect.pt/v1/webhooks/{id} \
  -H "Authorization: Bearer $CCONNECT_KEY" \
  -d '{"enabled": true}'

Rodar o segredo

Também no painel. O segredo novo aparece uma vez, e as entregas que já estavam a caminho foram assinadas com o anterior: o teu sistema vai recusá-las se já tiver mudado. Se isso te incomodar, aceita as duas assinaturas durante alguns minutos antes de largares a antiga.