Webhooks
Em vez de fazer polling, inscreva-se em eventos de saída: o Kinmu envia um POST para o seu endpoint HTTPS quando algo relevante acontece. Cada entrega vai assinada segundo a convenção Standard Webhooks — sempre verifique a assinatura antes de processar o evento.
A gestão de endpoints exige o scope webhooks:manage e é feita pelo painel ou via os endpoints /v1/webhook-endpoints.
Inscrição
Crie um endpoint informando sua URL (HTTPS) e os eventos que interessam:
curl -s -X POST "https://api.kinmu.app/v1/webhook-endpoints" \
-H "Authorization: Bearer kinmu_sk_live_…" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-app.example.com/webhooks/kinmu",
"events": ["absence.approved", "checkin.created"],
"description": "Sync con nuestro ERP"
}'A resposta inclui o segredo de assinatura (whsec_…), visível uma única vez. Guarde-o: você precisa dele para verificar as assinaturas.
Gestão disponível: GET (lista), GET /{id}, PATCH /{id} (eventos/estado), DELETE /{id}, POST /{id}/test (envia um ping), GET /{id}/deliveries (últimas entregas) e POST /{id}/deliveries/{deliveryId}/retry (reenfileira uma entrega específica). Máximo de 5 endpoints ativos por empresa.
Eventos
employee.created, employee.updated, employee.terminated, checkin.created, absence.requested, absence.approved, absence.denied, absence.cancelled, vacation_balance.updated, report.completed, ping.
Payload do evento
{ "id": "evt_…", "type": "absence.approved", "created_at": "…", "company_id": "…", "data": { … } }data carrega ids públicos + estado (o mínimo); reidrate via GET o recurso completo quando precisar de todos os campos.
Verificação da assinatura
Cada entrega chega com três headers:
| Header | Conteúdo |
|---|---|
webhook-id | Id único do evento (idempotência no seu receptor). |
webhook-timestamp | Timestamp Unix do envio. |
webhook-signature | v1,<assinatura> (pode haver várias, separadas por espaço). |
Algoritmo: assinatura = base64( HMAC_SHA256( key, "{webhook-id}.{webhook-timestamp}.{corpo_bruto}" ) ), com o prefixo v1,.
A key é a parte após whsec_ do segredo (exibido uma única vez na criação do webhook), decodificada de base64 para bytes. Assine sobre o corpo bruto (os bytes exatos recebidos), não sobre o JSON re-serializado.
Verificação (rejeite se não coincidir ou se webhook-timestamp divergir > 5 min do seu relógio):
Node.js
const crypto = require('crypto');
function verify(secret, headers, rawBody) {
const id = headers['webhook-id'];
const ts = headers['webhook-timestamp'];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // ±5 min
const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64');
const expected = 'v1,' + crypto
.createHmac('sha256', key)
.update(`${id}.${ts}.${rawBody}`)
.digest('base64');
return headers['webhook-signature']
.split(' ')
.some(sig => crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)));
}Verifique e assine sobre o corpo bruto (os bytes exatos recebidos), não sobre o JSON re-serializado — qualquer reformatação invalida a assinatura. Use o webhook-id como chave de idempotência no seu receptor para descartar reenvios.
Novas tentativas
Em caso de falha (ou resposta ≠ 2xx), o Kinmu tenta de novo com backoff: 1 min, 5 min, 30 min, 2 h, 12 h, 24 h. Responda 2xx rápido; processe async se demorar. Um endpoint que falha por 7 dias seguidos é desativado automaticamente.
Você pode reenfileirar manualmente uma entrega que falhou com POST /v1/webhook-endpoints/{id}/deliveries/{deliveryId}/retry (use o id da entrega que aparece em GET /{id}/deliveries).
Boas práticas
Responda rápido, processe em background
Verifique a assinatura, enfileire o trabalho e responda 2xx imediatamente.
Sempre verifique a assinatura
Não processe nenhum payload sem verificar webhook-signature. Trate o segredo como uma credencial.
Seja idempotente
Deduplique por webhook-id. Reenvios são normais.
Teste com ping
Use POST /v1/webhook-endpoints/{id}/test para receber um evento ping e validar sua integração de ponta a ponta.