API de capture
Todo en Kilden entra por un único endpoint:
POST https://ingest.kilden.io/captureContent-Type: application/jsonLos SDKs lo usan por debajo; puedes llamarlo directamente desde cualquier backend, script o integración. No hay otro camino de escritura.
Solicitud
Sección titulada «Solicitud»El body es siempre un batch — un evento solo es un batch de uno:
{ "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 | Obligatorio | Notas |
|---|---|---|
write_key |
sí | Key pública o secreta, en el body (no en un header). Las secret keys marcan los eventos como hechos server-side — ver Niveles de confianza |
sent_at |
no | Cuándo envió el cliente la request. Se usa solo para corregir el desfase del reloj del cliente: real_time ≈ timestamp + (server_now − sent_at) |
batch |
sí | De 1 a 1000 eventos |
identity_token |
no | Slot alternativo para el JWT de verificación de identidad cuando un header es imposible (sendBeacon). El header Authorization gana si están ambos |
Por evento:
| Campo | Obligatorio | Notas |
|---|---|---|
uuid |
sí | Un UUID válido, generado por el cliente. Usa UUID v7. Es la idempotency key: los reintentos con el mismo uuid se deduplican, así que reintentar ante cualquier fallo es siempre seguro |
event |
sí | Nombre del evento, ≤ 200 caracteres. Los nombres con prefijo $ están reservados para el sistema |
distinct_id |
sí | ≤ 512 caracteres. UUID v7 con prefijo anon_ = anónimo; cualquier otra cosa se trata como un id de usuario identificado |
properties |
no | Cualquier objeto JSON. Nunca se valida contra un schema — el sobre está tipado, el payload es tuyo |
timestamp |
no | ISO 8601. Por defecto la hora de recepción del servidor; se corrige con sent_at cuando están ambos |
Headers:
Authorization: Bearer <jwt>— token de verificación de identidad para todo el batch (un batch pertenece a una sola sesión de navegador). Máx. 4096 bytes.Content-Encoding: gzip— soportado y recomendado para batches grandes.
Límites: body de la request ≤ 5 MiB, batch ≤ 1000 eventos.
Respuesta
Sección titulada «Respuesta»200 apenas el batch se valida y encola (capture nunca bloquea esperando el procesamiento posterior):
{ "status": "ok" }Los errores son texto plano, no JSON:
| Estado | Significado |
|---|---|
400 |
Request 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 — ver orígenes permitidos |
405 |
Método distinto de POST/OPTIONS |
Los fallos de validación rechazan el batch completo — corrige y reintenta (los UUIDs hacen que sea seguro).
Ejemplo server-side
Sección titulada «Ejemplo server-side»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" }] }'Los eventos enviados con una secret key se marcan source=server y verified=true — la secret key es la autenticación. Nunca incrustes una secret key en un navegador o app móvil; para eso están las keys públicas.
/capture es un endpoint de escritura público, abierto a CORS por diseño:
- Cada respuesta lleva
Access-Control-Allow-Origin: *(sin credenciales). - El preflight
OPTIONSresponde204conAccess-Control-Allow-Methods: POST,Access-Control-Allow-Headers: Content-Type, Authorization, Content-Encoding,Access-Control-Max-Age: 86400.
Orígenes permitidos
Sección titulada «Orígenes permitidos»Una write key pública es visible en el código fuente de tu página, así que cualquiera podría copiarla. Para evitar que otros sitios contaminen tus datos, configura los orígenes permitidos en la configuración del proyecto: cuando la lista no está vacía, las requests de navegador cuyo Origin no coincida reciben 403.
- Patrones:
scheme://host[:port], con wildcards de subdominio (https://*.example.com— no coincide con el apex; lista ambos si lo necesitas). - Lista vacía (default) = permitir todo.
- Las requests sin header
Origin(curl, backends, apps móviles) siempre pasan — ese vector lo cubren las secret keys y la verificación de identidad, no el matching de Origin. Esto es reducción de ruido contra la reutilización real de keys en navegadores, no una frontera de seguridad.