Webhooks
Reenvios e boas práticas
Como a Koku reenvia webhooks, como processar sem duplicar e como recuperar eventos perdidos.
Responda 2xx rápido
A entrega conta como feita quando o seu endpoint responde com status 2xx em até 5 segundos. Qualquer outro status, redirecionamento (3xx), tempo esgotado ou erro de conexão conta como falha e gera nova tentativa.
- Confira a assinatura, grave o evento numa fila ou tabela e responda
200na hora. - Faça o processamento pesado (liberar pedido, enviar e-mail, emitir nota) em segundo plano.
- Não siga com redirecionamentos: cadastre a URL final.
Reenvios automáticos
Se a entrega falhar, a Koku tenta de novo, com intervalos que começam em poucos segundos e dobram a cada falha (com uma variação aleatória), até 8 tentativas por evento. Esgotadas as tentativas, a entrega fica como dead_letter.
Se um endpoint falhar várias vezes seguidas, a Koku pausa as entregas para ele por um tempo (paused_until em Listar endpoints) e volta a testar depois; a pausa cresce enquanto as falhas continuarem. Quando o endpoint volta a responder, tudo segue normalmente.
Acompanhe o resultado de cada tentativa:
curl -X GET 'https://api.kokupay.com/v1/webhooks/deliveries?status=delivered&limit=20' \
-H "Authorization: Bearer $KOKU_API_KEY"const response = await fetch('https://api.kokupay.com/v1/webhooks/deliveries?status=delivered&limit=20', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.KOKU_API_KEY}`,
},
});
const data = await response.json();
console.log(response.status, data);import os
import requests
response = requests.request(
"GET",
"https://api.kokupay.com/v1/webhooks/deliveries?status=delivered&limit=20",
headers={
"Authorization": f"Bearer {os.environ['KOKU_API_KEY']}",
},
timeout=30,
)
print(response.status_code, response.json())<?php
$ch = curl_init('https://api.kokupay.com/v1/webhooks/deliveries?status=delivered&limit=20');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KOKU_API_KEY'),
],
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo $status, PHP_EOL;
print_r($data);{
"items": [
{
"id": "c58a2e1f-7d39-4b6c-9e04-2a1f8d7c3b65",
"endpoint_id": "71c3e9a5-4f2d-4b8e-a06c-9d5e2f1b7a38",
"endpoint_url": "https://loja.example.com/webhooks/koku",
"event_id": "evt_2f6b1c9e8a4d4e7f9b3c5a1d0e6f8b27",
"event_type": "charge.paid",
"status": "delivered",
"attempts": 1,
"last_response_status": 200,
"last_response_ms": 84,
"last_error": null,
"last_attempt_at": "2026-10-07T15:32:12.000Z",
"next_attempt_at": null,
"delivered_at": "2026-10-07T15:32:12.000Z",
"created_at": "2026-10-07T15:32:11.000Z"
}
],
"next_cursor": null
}Processe cada evento uma vez (idempotência no consumo)
O mesmo evento pode chegar mais de uma vez (por exemplo, quando o seu servidor processou, mas a resposta não chegou à Koku). O id do evento (x-koku-event-id) é o mesmo em todas as tentativas:
- Ao receber, procure o
idnuma tabela de eventos processados. - Se já existe, responda
200e não faça nada. - Se não existe, grave o
ide processe, na mesma transação do seu banco.
Os eventos também podem chegar fora de ordem. Não dependa da ordem de chegada: para decidir, consulte o estado atual do recurso.
Confirme pela consulta
O webhook avisa; a API confirma. Antes de liberar um pedido, consulte a cobrança com Consultar cobrança e confira status, valor e order_reference. Isso protege contra evento forjado (caso a verificação de assinatura falhe por algum descuido) e contra eventos fora de ordem.
Recupere o que se perdeu
Se o seu endpoint ficou fora do ar por mais tempo que os reenvios, nada se perde: todos os eventos ficam em Listar eventos. Uma rotina periódica (por exemplo, a cada 15 minutos) que lê os eventos recentes e processa os que faltam fecha qualquer lacuna. Para cobranças em aberto, consultar a cobrança também resolve.
Segurança do endpoint
- Só HTTPS, com certificado válido.
- Verifique a assinatura em toda requisição; recuse sem assinatura válida.
- Não exponha detalhes de erro na resposta ao webhook.
- Não confie em IP de origem: a assinatura é a garantia.