Pular para o conteúdo

Entregas e novas tentativas

Cada evento vira uma entrega para cada endpoint ligado e inscrito nele. A entrega tem a sua própria vida: tentativas, situação e resultado, que você acompanha pelo log.

Cada tentativa tem 15 segundos para terminar. O que vale é só o código HTTP:

RespostaO que acontece
2xxEntregue. Acabou
410O endpoint é desligado na hora, e a entrega fica como falha, sem nova tentativa
429, 502, 503, 504Falha. A próxima tentativa respeita o Retry-After, se vier
3xxFalha. Redirecionamento nunca é seguido
Qualquer outro códigoFalha, e tenta de novo pela agenda
Sem respostaFalha (tempo esgotado, conexão recusada, erro de TLS, DNS), e tenta de novo

O corpo da resposta não precisa de nada: um 200 vazio basta. Os cabeçalhos da resposta não são lidos, a não ser o Retry-After, e não são guardados. Do corpo, até 2 KB ficam guardados no log de entregas, então não responda com dado sensível.

Use o 410 só quando o endereço deixou de existir de vez: ele desliga o endpoint para todos os eventos, não só para aquele.

Depois da primeira tentativa, as seguintes esperam:

TentativaEspera depois da anterior
2ª5 segundos
3ª5 minutos
4ª30 minutos
5ª2 horas
6ª5 horas
7ª10 horas
8ª14 horas
9ª20 horas
10ª24 horas

Cada espera varia 10% para cima ou para baixo, ao acaso, para muitas entregas que falharam juntas não voltarem todas no mesmo segundo. São 10 tentativas em pouco mais de 3 dias. Se a décima falhar, a entrega fica como failed, e você ainda pode reenviá-la enquanto o evento existir.

Nas respostas 429, 502, 503 e 504, o Retry-After é respeitado, em segundos ou como data HTTP. Ele só aumenta a espera: a próxima tentativa sai no que for mais tarde entre a agenda e o Retry-After. O teto é de 24 horas, então um Retry-After maior vale 24 horas. Valor inválido é ignorado, e ele não acrescenta tentativa: depois da décima, não há outra.

O endpoint que só falhou por 3 dias seguidos é desligado. A contagem começa na primeira falha e só uma entrega com sucesso a zera: um endpoint que falha às vezes e acerta às vezes nunca é desligado por isso.

Nos dois casos de desligamento automático (3 dias de falha e 410), dono e administradores recebem um e-mail com o domínio do endpoint e a data. O endpoint aparece com status: "disabled" e disabled_reason failing ou gone.

Os valores de disabled_reason são quatro: manual (alguém desligou, pelo painel ou por PATCH), failing (3 dias de falha), gone (o destino respondeu 410) e emergency_key_rotation (pausado por segurança: a chave de API que inscreveu o endpoint passou pela rotação “Parar agora” ou, quando a inscrição no programa do GitHub estiver ativa, foi revogada automaticamente por ter sido achada publicada). Com o endpoint ligado, o campo é null.

Enquanto o endpoint está desligado:

  • nenhum evento novo gera entrega para ele, e esses eventos não ficam guardados esperando por ele;
  • a entrega que já estava na fila é fechada sem envio, com o erro endpoint_disabled.

Para religar, PATCH /public/v1/webhook_endpoints/{id} com "status": "enabled". Religar zera a contagem de falhas. Os eventos do período em que ele esteve desligado não chegam a esse endpoint e não podem ser reenviados para ele, porque nenhuma entrega foi criada. Para recuperar o que mudou nesse período, sincronize com updated_after (veja Boas práticas). O reenvio manual vale para as entregas que falharam antes do desligamento.

GET /public/v1/webhook_endpoints/{id}/deliveries lista as entregas do endpoint, das mais novas para as mais antigas, com filtro por status (pending, succeeded, failed) e por event_type. Cada entrega traz a situação, o número de tentativas, a próxima tentativa, o código HTTP e a duração da última, até 2 KB do corpo da resposta e, quando não houve resposta, o motivo em error.

A lista segue a mesma regra de GET /public/v1/events: só aparecem as entregas de eventos dos módulos que a chave lê (<modulo>:read) e que o membro dela pode ver no painel.

Os valores de error:

errorO que houve
timeoutA tentativa passou de 15 segundos
connection_refusedO servidor recusou a conexão
connection_resetA conexão caiu no meio
host_unreachableNão foi possível chegar ao servidor
dns_failedO nome não resolveu
tls_errorCertificado inválido, vencido ou autoassinado, ou falha no TLS
redirect_not_followedO servidor respondeu 3xx
blocked_targetO nome passou a apontar para um endereço interno
blocked_protocol, blocked_port, credentials_in_url, invalid_urlA URL não passa mais na política de destino
network_errorOutra falha de rede
endpoint_disabledO endpoint estava desligado; a entrega foi fechada sem envio
subscriber_access_lostQuem inscreveu o endpoint não lê mais o módulo do evento; fechada sem envio
plan_without_apiO plano da empresa não tem mais a API; fechada sem envio
internal_errorFalha do nosso lado. Ela segue a agenda de novas tentativas como qualquer falha

Quando houve resposta HTTP, error vem null e o motivo está em response_status_code (o 3xx é a exceção: vem com redirect_not_followed). endpoint_disabled, subscriber_access_lost e plan_without_api não gastam tentativa: a entrega é fechada sem ser enviada.

POST /public/v1/webhook_endpoints/{id}/deliveries/{delivery_id}/retry responde 202 e cria uma entrega nova do mesmo evento para o mesmo endpoint. A entrega anterior fica como estava, com o histórico dela, e a nova tem retry_number maior.

O reenvio é um pedido explícito seu: ele confere de novo o acesso de quem inscreveu o endpoint, mas não confere se o endpoint ainda está inscrito naquele tipo de evento. Uma entrega de sale.paid pode ser reenviada mesmo que o endpoint não assine mais sale.paid.

  • A entrega nova segue o mesmo caminho de qualquer outra: assinada com o segredo atual, com a mesma conferência de destino e a mesma agenda de novas tentativas se falhar.
  • O webhook-id e o id do corpo são os mesmos do evento original. Se o seu sistema já tinha processado aquele evento, é pelo webhook-id que ele reconhece a repetição.
  • O corpo é o do evento, como ele foi registrado. O objeto não é relido: para o estado de agora, consulte a API.

As recusas:

RespostaQuando
404 resource_not_foundA entrega não existe, é de outro endpoint, ou o evento tem mais de 30 dias
409 conflict com param: "status"O endpoint está desligado. Religue antes
409 conflictJá existe uma entrega desse evento para esse endpoint na fila (a original ainda tentando, ou outro reenvio). Espere ela terminar
409 conflictQuem inscreveu o endpoint não lê mais o módulo do evento. Devolva o acesso ou edite o endpoint com quem tem
403 permission_missingA chave não tem o <modulo>:read de algum evento que o endpoint assina (a mesma regra da troca de URL)
403 plan_feature_unavailableO plano da empresa não tem a API

Eventos e entregas ficam guardados por 30 dias e depois são apagados. Esse é o prazo do log de entregas, de GET /public/v1/events e do reenvio manual.

  • Boas práticas: como montar o recebimento para aguentar repetição e desordem.
  • Referência: as rotas de entregas e de eventos, campo a campo.