Skip to Content
Webhooks

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:

HeaderConteúdo
webhook-idId único do evento (idempotência no seu receptor).
webhook-timestampTimestamp Unix do envio.
webhook-signaturev1,<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):

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.

Last updated on