KuikCodeDocs
APIGuías

Recibe escaneos en tu CRM

Recibe cada escaneo en tu endpoint en el momento en que ocurre, verifícalo y guárdalo junto al contacto o la campaña a la que pertenece.

Hay dos formas de sacar los datos de escaneos: los webhooks te envían cada escaneo en menos de un segundo (Business), y GET /scans te permite traerlos por páginas cuando tú quieras (PRO y superiores). La mayoría de las integraciones con CRM usan el webhook para tener datos frescos y la consulta periódica para conciliar.

Opción A: webhooks

1. Prepara un endpoint

Una URL https en un nombre de host público que responda 2xx rápido. Haz el trabajo después de responder; las entregas tienen un tiempo de espera de diez segundos y no se reintentan.

2. Regístralo y conecta códigos

curl -X POST https://api.kuikcode.com/v1/webhooks \
  -H "Authorization: Bearer kc_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://crm.example.com/hooks/kuikcode", "codeIds": ["K02bEPC2SmtopwPr6S-jt", "Zq9vX1mN4kLp8rTb2cWd0"] }'

La respuesta incluye el id del endpoint y su secret. Existe un endpoint por URL; si vuelves a enviar la misma URL, recibes el que ya existe. PATCH /webhooks/{id} con codeIds reemplaza el conjunto conectado, así que agregar un código requiere leer, modificar y escribir.

3. Verifica cada entrega

POST /hooks/kuikcode
X-KuikCode-Event: scan.created
X-KuikCode-Delivery: 3f1c9a4e-0d5b-4c7e-9a2f-6b8d1e0c2a44
X-KuikCode-Timestamp: 1757251331
X-KuikCode-Signature: t=1757251331,v1=8c2e...

{ "event": "scan.created", "timestamp": "...", "code": { "id": "Ab3dE9xYz", "name": "Front window" },
  "scan": { "scanId": "...", "country": "US", "region": "NJ", "city": "Montclair", "deviceType": "mobile",
            "os": "iOS", "browser": "Safari", "language": "en", "timezone": "America/New_York",
            "destination": "https://example.com/summer-menu", "matchedRule": null } }

La firma es t=<unix seconds>,v1=<hex>, donde v1 es el HMAC-SHA256 de <t>.<raw body> con el secreto. Revisa que la marca de tiempo no tenga más de cinco minutos y luego compara en tiempo constante:

import { createHmac, timingSafeEqual } from "node:crypto"

export function verify(rawBody, header, secret, now = Math.floor(Date.now() / 1000)) {
  const t = Number(header?.match(/(?:^|,)t=(\d+)/)?.[1])
  const sig = header?.match(/(?:^|,)v1=([0-9a-f]+)/)?.[1]
  if (!sig || !Number.isFinite(t) || Math.abs(now - t) > 300) return false
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")
  return sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
}

Rechaza todo lo que falle. Cada entrega llega al menos una vez y se reintenta si falla, así que guarda X-KuikCode-Delivery y omite los valores que ya procesaste. El secreto viene en la respuesta de la creación; después, POST /webhooks/{id}/secret lo vuelve a mostrar y POST /webhooks/{id}/rotate-secret lo reemplaza con 24 horas de convivencia. Todos los detalles están en Webhooks de escaneos. code.id en el payload es el código corto impreso; relaciónalo con tu registro mediante la correspondencia que guardaste al crear los códigos.

4. Envía una prueba

POST /webhooks/{id}/test envía un evento de muestra con "test": true e informa el estado que devolvió tu servidor. Úsalo después de cada despliegue del endpoint.

Opción B: consulta con GET /scans

Para una sincronización nocturna o para recuperar datos anteriores, recorre los escaneos por páginas con una ventana de tiempo y un cursor:

curl "https://api.kuikcode.com/v1/scans?from=2026-09-01T00:00:00Z&to=2026-09-07T00:00:00Z&limit=100" \
  -H "Authorization: Bearer kc_live_..."

Sigue next_cursor hasta que sea null. Filtra por codeId, folderId o tag para acotar la consulta. Las ventanas se recortan al historial que incluye el plan, y la respuesta lo indica con clamped: true. Cada fila incluye los mismos campos que el payload del webhook, más la hora del escaneo.

Qué te dice un escaneo sobre una persona

Nada que la identifique. Los escaneos incluyen país, región y ciudad, dispositivo, sistema operativo, navegador e idioma, el destino que se sirvió y la regla inteligente que lo eligió. No hay dirección IP ni cookie. Para vincular un escaneo con un contacto, pon el contacto o la campaña en el propio código: un código por representante, por envío o por tienda, y parámetros UTM en el destino para tu propia analítica.

Contactos de formularios de KuikPage

Las respuestas de formularios son un flujo aparte: cada una envía form.submission a la URL del webhook del formulario con los campos identificados por sus etiquetas, y GET /submissions las lista. Consulta Webhooks de formularios.

En esta página