Developer docs
Integra POS, nominas y sistemas externos con Oktavia.
Oktavia Connect es la capa de integracion para enviar datos operativos a Oktavia y recibir eventos firmados desde Oktavia. Esta documentacion esta pensada para partners POS, herramientas de nomina, gestorias y sistemas internos de cadenas hosteleras.
Version
2026-06-01
Spec API
JSON publicoOpenAPI
Descargar contratoPostman
Importar coleccionInsomnia
Importar workspaceEstado
Usando fallback localDocs para integradores y agentes
Ademas de esta guia visual, Oktavia publica una version Markdown y un indice `llms.txt` para que equipos tecnicos, agentes de codigo y herramientas AI puedan encontrar rapidamente el contrato de Connect.
Quickstart de integracion
El flujo recomendado es empezar siempre en sandbox, validar mapeos con el cliente y solo despues activar produccion. Las credenciales se generan por conexion y por entorno.
1. Crear conexion
El cliente crea una conexion en Oktavia Connect y comparte connectionId, API key y secret con el partner.
2. Enviar evento sandbox
El partner envia un payload de prueba con idempotency key unica, timestamp y firma HMAC.
3. Validar normalizacion
Oktavia registra hash, resumen y estado. El cliente revisa que centro, fecha e importes se interpreten bien.
4. Pasar a produccion
Se activa la conexion de produccion, se limita el scope necesario y se monitorizan entregas y errores.
Autenticacion, firma e idempotencia
Las llamadas inbound usan API key y firma HMAC. Los webhooks outbound de Oktavia tambien viajan firmados para que el partner pueda validar origen e integridad. La idempotencia evita duplicar cierres diarios o importes si el partner reintenta.
Headers inbound
- x-oktavia-key
- API key de conexion
- x-oktavia-signature
- HMAC SHA-256
- x-oktavia-timestamp
- Unix ms
- x-idempotency-key
- Clave unica por evento
Usa una idempotency key estable, por ejemplo cierre-centro-fecha. Si reenvias el mismo evento, Oktavia lo reconocera como duplicado.
Calculo de firma
Algoritmo: HMAC-SHA256. Payload firmado: <timestamp>.<raw-json-body>
const body = JSON.stringify(payload);
const signedPayload = `${timestamp}.${body}`;
const signature = hmacSha256(secret, signedPayload);Verificacion Node.js
import crypto from 'node:crypto';
function verifyOktaviaSignature(secret, timestamp, body, signature) {
const expected = crypto.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}API Reference
Esta es la zona de trabajo para el desarrollador externo: contrato OpenAPI, colecciones importables, guia plana y estado publico. La referencia interactiva completa puede vivir en `developers.oktavia.app` cuando separemos el portal en subdominio propio.
Eventos inbound
Envia eventos POS y demanda a este endpoint con firma HMAC, idempotencia y un `eventType` soportado. Todos los eventos usan la misma envolvente; el contenido de `payload` depende del tipo de evento.
Endpoint
POST /connect/inbound/:connectionId/events
Tipos soportados
El sistema externo debe llamar a Oktavia cuando genere un nuevo dato operativo. Oktavia solo procesa eventos con firma valida, clave de idempotencia y campos obligatorios.
{
"eventType": "pos.daily_close",
"externalId": "close-2026-06-01-main-site",
"occurredAt": "2026-06-01T23:05:00.000Z",
"payload": {
"date": "2026-06-01",
"center": "main-site",
"total": 4180.5,
"currency": "EUR",
"channels": [
{
"name": "Comida",
"total": 2660.1
},
{
"name": "Bebida",
"total": 1520.4
}
]
}
}Contrato de payload
Incluye siempre los campos minimos del evento. Los campos adicionales deben viajar dentro de `payload` y se trataran como extension del proveedor hasta que exista un mapeo aprobado.
Envolvente comun
| Campo | Uso | Descripcion |
|---|---|---|
| eventType | Si | Tipo funcional del evento. Ejemplo: pos.daily_close. |
| externalId | Recomendado | Identificador estable del evento en el sistema origen. |
| occurredAt | Recomendado | Fecha/hora real del evento en ISO 8601. Si no llega, Oktavia usa recepcion. |
| payload.date | Si | Fecha operativa en formato ISO YYYY-MM-DD. |
| payload.center | Si | Nombre o codigo externo del centro. Se mapea en Oktavia Connect. |
| payload.total | Segun evento | Importe total, unidades o metrica principal del evento. |
| payload.currency | Si hay importe | Moneda ISO. Para Espana normalmente EUR. |
Payloads por tipo de evento
| Evento | Uso | Minimos | Opcionales |
|---|---|---|---|
| pos.daily_close | Cierre diario del POS por centro y fecha operativa. | payload.date, payload.center, payload.total, payload.currency | payload.channels, payload.taxes, payload.ticketCount, payload.serviceBreakdown |
| pos.sales_interval | Ventas agregadas por franjas para alimentar demanda y planificacion. | payload.date, payload.center, payload.intervals[] | payload.intervals[].food, payload.intervals[].drinks, payload.intervals[].tickets |
| pos.products | Productos o categorias vendidas para analisis de demanda y mix de venta. | payload.date, payload.center, payload.items[] | payload.items[].category, payload.items[].quantity, payload.items[].grossTotal |
| reservations.forecast | Reservas o prevision de ocupacion futura por centro y franja. | payload.date, payload.center, payload.slots[] | payload.slots[].covers, payload.slots[].status, payload.slots[].source |
Cierre diario
{
"eventType": "pos.daily_close",
"externalId": "close-2026-06-01-main-site",
"occurredAt": "2026-06-01T23:05:00.000Z",
"payload": {
"date": "2026-06-01",
"center": "main-site",
"total": 4180.5,
"currency": "EUR",
"channels": [
{
"name": "Comida",
"total": 2660.1
},
{
"name": "Bebida",
"total": 1520.4
}
]
}
}Ventas por franja
{
"eventType": "pos.sales_interval",
"externalId": "sales-2026-06-01-main-site-15-00",
"occurredAt": "2026-06-01T15:05:00.000Z",
"payload": {
"date": "2026-06-01",
"center": "main-site",
"intervals": [
{
"start": "13:00",
"end": "14:00",
"total": 910.2,
"food": 620.1,
"drinks": 290.1,
"tickets": 34
},
{
"start": "14:00",
"end": "15:00",
"total": 1240.4,
"food": 870.2,
"drinks": 370.2,
"tickets": 41
}
],
"currency": "EUR"
}
}Ejemplo cURL
curl -X POST "https://api.oktavia.app/connect/inbound/{connectionId}/events" \
-H "content-type: application/json" \
-H "x-oktavia-key: ok_live_..." \
-H "x-oktavia-timestamp: 1780300800000" \
-H "x-idempotency-key: close-2026-06-01-main-site" \
-H "x-oktavia-signature: <hmac-sha256>" \
-d '{"eventType":"pos.daily_close","externalId":"close-2026-06-01-main-site","occurredAt":"2026-06-01T23:05:00.000Z","payload":{"date":"2026-06-01","center":"main-site","total":4180.5,"currency":"EUR"}}'Respuestas y errores
Un evento aceptado no significa necesariamente que ya haya impactado en planificacion; significa que Oktavia lo ha recibido, verificado y registrado para procesarlo.
| Codigo | Significado |
|---|---|
| 202 | Evento aceptado y pendiente/procesado por Oktavia. |
| 200 | Evento duplicado reconocido por idempotency key. |
| 400 | Payload invalido o campo obligatorio ausente. |
| 401 | API key, timestamp o firma incorrecta. |
| 403 | Scope insuficiente o conexion no activa. |
| 409 | Conflicto de idempotencia con payload distinto. |
{
"id": "evt_01J...",
"status": "accepted",
"eventType": "pos.daily_close",
"payloadHash": "sha256_hash",
"duplicate": false
}Nomina y gestoria
Las conexiones de tipo nomina son salientes desde Oktavia: el cliente genera paquetes firmados con horas validadas y ausencias aprobadas para que gestoria, ERP o proveedor laboral los consuma sin rehacer calculos manuales.
Horas validadas
POST /organizations/:organizationId/connect/connections/:connectionId/payroll-hours-export
Genera un paquete de horas ordinarias, complementarias, extras, nocturnidad, festivos y desviaciones del periodo.
payroll:hours:readAusencias aprobadas
POST /organizations/:organizationId/connect/connections/:connectionId/payroll-absences-export
Genera un paquete de vacaciones, permisos, bajas e incidencias aprobadas para contrastar con nomina.
payroll:absences:readRequest
{
"startDate": "2026-05-01",
"endDate": "2026-05-31"
}Horas validadas
{
"format": "oktavia.payroll.hours.v1",
"period": {
"startDate": "2026-05-01",
"endDate": "2026-05-31"
},
"rows": [
{
"employeeCode": "employee-001",
"employeeName": "Trabajador de ejemplo",
"center": "main-site",
"ordinaryMinutes": 9120,
"complementaryMinutes": 0,
"overtimeMinutes": 120,
"nightMinutes": 90,
"holidayMinutes": 0
}
]
}Ausencias aprobadas
{
"format": "oktavia.payroll.absences.v1",
"period": {
"startDate": "2026-05-01",
"endDate": "2026-05-31"
},
"rows": [
{
"employeeCode": "employee-003",
"employeeName": "Responsable de ejemplo",
"type": "vacation",
"startDate": "2026-05-20",
"endDate": "2026-05-24",
"approvedAt": "2026-05-12T10:30:00.000Z"
}
]
}Webhooks outbound
Configura una URL HTTPS para recibir eventos firmados de Oktavia cuando se publiquen cuadrantes, se validen fichajes, se aprueben ausencias o se generen exportaciones de nomina.
Eventos disponibles
{
"type": "schedule.published",
"occurredAt": "2026-06-01T08:00:00.000Z",
"data": {
"scheduleId": "schedule_id",
"centerId": "center_id",
"weekStart": "2026-06-15",
"weekEnd": "2026-06-21"
}
}| Header | Descripcion |
|---|---|
| x-oktavia-event | Tipo de evento enviado por Oktavia. |
| x-oktavia-signature | Firma HMAC SHA-256 calculada con el secret de la conexion. |
| x-oktavia-timestamp | Timestamp usado para firmar el payload. |
| x-oktavia-delivery-id | Identificador de entrega para trazabilidad y soporte. |
Operacion, reintentos y retencion
Reintentos
5
5 a 60 minutos, creciente por intento.
Retencion payload
30 dias
Se conservan hashes, resumen, estado e intentos para auditoria.
Scopes
8
Permisos granulares por conexion externa.
Checklist de seguridad y versionado
Seguridad minima del partner
- Validar siempre la firma HMAC antes de procesar el body.
- Rechazar timestamps demasiado antiguos para reducir riesgo de replay.
- Guardar y deduplicar idempotency keys durante al menos 24 horas.
- Usar HTTPS en produccion. Oktavia no acepta webhooks no seguros salvo localhost.
- Rotar credenciales si se comparten por error o cambia el proveedor.
- Pedir solo los scopes necesarios para la integracion.
Compatibilidad y cambios
- La version de spec indica el contrato vigente de Connect.
- Los nuevos campos se anadiran de forma compatible siempre que sea posible.
- Los consumidores deben ignorar campos desconocidos.
- Los cambios incompatibles se publicaran como nueva version antes de activarse.
Checklist de certificacion de partner
Antes de pasar una integracion a produccion, Oktavia revisa estos puntos con el partner y el cliente para evitar datos duplicados, credenciales expuestas o mapeos ambiguos.
Credenciales
- Usa credenciales separadas para sandbox y produccion.
- No expone apiKey ni secret en clientes publicos o repositorios.
- Tiene procedimiento para rotar credenciales si hay una filtracion.
Firma e idempotencia
- Firma cada request con HMAC-SHA256 usando el body JSON exacto enviado.
- Rechaza timestamps antiguos en webhooks outbound.
- Envia x-idempotency-key estable para eventos que puedan reintentarse.
Calidad de datos
- Envia fechas ISO y moneda ISO cuando hay importes.
- Mantiene identificadores externos estables para cierres, productos y centros.
- Mapea centro, fecha operativa e importes con el cliente antes de produccion.
Operacion
- Implementa reintentos con backoff ante errores 5xx o timeouts.
- Registra requestId, payloadHash y respuesta de Oktavia para soporte.
- Tiene alertas si una integracion empieza a fallar en produccion.
Herramienta local de firma HMAC
Usa este bloque para comprobar si tu firma coincide con la que espera Oktavia. El secret no se envia al servidor: el calculo se hace en tu navegador.
Firma generada
Pendiente de generar
Try it sandbox
Envia un evento inbound de prueba al endpoint sandbox de Oktavia. Usa las credenciales que el cliente haya generado para esa conexion en Oktavia Connect.
Antes de enviar
- 1. El cliente crea una conexion sandbox en Oktavia Connect.
- 2. Oktavia genera `connectionId`, API key sandbox y secret sandbox.
- 3. El partner pega esas credenciales aqui y envia el evento de prueba.
Endpoint Oktavia
https://api.oktavia.app/connect/inbound/{connectionId}/events
Usa `https://api.oktavia.app`. No uses `localhost` fuera de desarrollo interno ni pegues credenciales productivas en equipos compartidos.
Configuracion avanzada
Soporte para integradores
Si una integracion falla, Oktavia puede diagnosticarla mucho mas rapido si el partner aporta los identificadores tecnicos correctos. No hace falta enviar secretos ni payloads completos por correo.
Datos minimos
connectionId, entorno, fecha/hora UTC, eventType, externalId e idempotency key.
Trazabilidad
deliveryId o requestId, codigo HTTP, payloadHash y mensaje de error recibido.
Seguridad
Nunca compartas API keys, secrets ni documentos reales en tickets sin canal seguro.