Pular para o conteúdo

API de capture

Tudo no Kilden entra por um único endpoint:

POST https://ingest.kilden.io/capture
Content-Type: application/json

Os SDKs o usam por baixo dos panos; você pode chamá-lo diretamente de qualquer backend, script ou integração. Não existe outro caminho de escrita.

O corpo é sempre um batch — um evento único é um batch de um:

{
"write_key": "YOUR_WRITE_KEY",
"sent_at": "2026-07-11T12:00:00.000Z",
"batch": [
{
"uuid": "0197f9d2-5e5a-7cc3-b1a4-1f0e9a2b3c4d",
"event": "order_completed",
"distinct_id": "user_4821",
"properties": { "total": 49.9, "currency": "EUR" },
"timestamp": "2026-07-11T11:59:58.000Z"
}
]
}
Campo Obrigatório Notas
write_key sim Key pública ou secreta, no corpo (não em header). Keys secretas marcam os eventos como fatos server-side — veja Níveis de confiança
sent_at não Quando o cliente enviou a requisição. Usado apenas para corrigir o desvio de relógio do cliente: real_time ≈ timestamp + (server_now − sent_at)
batch sim 1 a 1000 eventos
identity_token não Slot de fallback para o JWT de verificação de identidade quando um header é impossível (sendBeacon). O header Authorization vence se ambos estiverem presentes

Por evento:

Campo Obrigatório Notas
uuid sim Um UUID válido, gerado pelo cliente. Use UUID v7. Esta é a chave de idempotência: retries com o mesmo uuid são deduplicados, então repetir a requisição diante de qualquer falha é sempre seguro
event sim Nome do evento, ≤ 200 caracteres. Nomes com prefixo $ são reservados para o sistema
distinct_id sim ≤ 512 caracteres. UUID v7 com prefixo anon_ = anônimo; qualquer outra coisa é tratada como id de usuário identificado
properties não Qualquer objeto JSON. Nunca validado por schema — o envelope é tipado, o payload é seu
timestamp não ISO 8601. Padrão: hora de recebimento no servidor; corrigido com sent_at quando ambos estão presentes

Headers:

  • Authorization: Bearer <jwt> — token de verificação de identidade para o batch inteiro (um batch pertence a uma sessão de navegador). Máx. 4096 bytes.
  • Content-Encoding: gzip — suportado e recomendado para batches grandes.

Limites: corpo da requisição ≤ 5 MiB, batch ≤ 1000 eventos.

200 assim que o batch é validado e enfileirado (o capture nunca bloqueia esperando o processamento downstream):

{ "status": "ok" }

Os erros são texto puro, não JSON:

Status Significado
400 Requisição malformada: invalid JSON body: …, invalid gzip body, write_key is required, batch must not be empty, batch exceeds 1000 events, batch[i]: uuid is not a valid UUID, batch[i]: event is required, batch[i]: event exceeds 200 chars, batch[i]: distinct_id is required, batch[i]: distinct_id exceeds 512 chars, batch[i]: properties is not valid JSON, identity token too large
401 unknown write_key
403 origin not allowed for this project — veja origens permitidas
405 Método diferente de POST/OPTIONS

Falhas de validação rejeitam o batch inteiro — corrija e reenvie (os UUIDs tornam isso seguro).

Terminal window
curl -X POST https://ingest.kilden.io/capture \
-H 'Content-Type: application/json' \
-d '{
"write_key": "sk_your_secret_key",
"sent_at": "2026-07-11T12:00:00Z",
"batch": [{
"uuid": "0197f9d2-5e5a-7cc3-b1a4-1f0e9a2b3c4d",
"event": "subscription_renewed",
"distinct_id": "user_4821",
"properties": {"plan": "pro", "mrr": 49},
"timestamp": "2026-07-11T12:00:00Z"
}]
}'

Eventos enviados com uma key secreta são marcados como source=server e verified=true — a key secreta é a autenticação. Nunca embuta uma key secreta em um navegador ou app mobile; é para isso que existem as keys públicas.

/capture é um endpoint público de escrita, aberto a CORS por design:

  • Toda resposta carrega Access-Control-Allow-Origin: * (sem credenciais).
  • O preflight OPTIONS responde 204 com Access-Control-Allow-Methods: POST, Access-Control-Allow-Headers: Content-Type, Authorization, Content-Encoding, Access-Control-Max-Age: 86400.

Uma write key pública fica visível no código-fonte da sua página, então qualquer um poderia copiá-la. Para impedir que outros sites poluam seus dados, configure origens permitidas nas configurações do projeto: quando a lista não está vazia, requisições de navegador cujo Origin não casa recebem 403.

  • Padrões: scheme://host[:port], com wildcards de subdomínio (https://*.example.com — não casa com o apex; liste os dois se precisar).
  • Lista vazia (padrão) = permitir tudo.
  • Requisições sem header Origin (curl, backends, apps mobile) sempre passam — esse vetor é coberto pelas keys secretas e pela verificação de identidade, não pela checagem de Origin. Isto é redução de ruído contra o reuso real de keys em navegadores, não uma fronteira de segurança.