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.

Docs 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.

Modelo cliente-partner

Un partner puede desarrollar contra sandbox sin acceder a datos reales. Las credenciales productivas siempre las emite el cliente desde su cuenta Oktavia y quedan limitadas a una conexión, un entorno y unos permisos concretos.

1. Partner prepara

Implementa firma, idempotencia y payloads usando documentación y sandbox.

2. Cliente autoriza

Crea la conexión, define scopes y comparte el paquete técnico con el proveedor.

3. Datos firmados

El proveedor envía o recibe eventos firmados con credenciales de esa conexión.

4. Control continuo

El cliente puede pausar, revocar o rotar credenciales en cualquier momento.

No existe una API key global con acceso a todos los clientes.

Este modelo reduce el riesgo operativo: el partner solo opera sobre lo que el cliente autoriza, la conexión queda auditada y cualquier incidencia puede aislarse sin comprometer otras integraciones.

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

pos.daily_closepos.sales_intervalpos.productsreservations.forecast

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

CampoUsoDescripcion
eventTypeSiTipo funcional del evento. Ejemplo: pos.daily_close.
externalIdRecomendadoIdentificador estable del evento en el sistema origen.
occurredAtRecomendadoFecha/hora real del evento en ISO 8601. Si no llega, Oktavia usa recepcion.
payload.dateSiFecha operativa en formato ISO YYYY-MM-DD.
payload.centerSiNombre o codigo externo del centro. Se mapea en Oktavia Connect.
payload.totalSegun eventoImporte total, unidades o metrica principal del evento.
payload.currencySi hay importeMoneda ISO. Para Espana normalmente EUR.

Payloads por tipo de evento

EventoUsoMinimosOpcionales
pos.daily_closeCierre diario del POS por centro y fecha operativa.payload.date, payload.center, payload.total, payload.currencypayload.channels, payload.taxes, payload.ticketCount, payload.serviceBreakdown
pos.sales_intervalVentas agregadas por franjas para alimentar demanda y planificacion.payload.date, payload.center, payload.intervals[]payload.intervals[].food, payload.intervals[].drinks, payload.intervals[].tickets
pos.productsProductos 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.forecastReservas 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.

CodigoSignificado
202Evento aceptado y pendiente/procesado por Oktavia.
200Evento duplicado reconocido por idempotency key.
400Payload invalido o campo obligatorio ausente.
401API key, timestamp o firma incorrecta.
403Scope insuficiente o conexion no activa.
409Conflicto 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:read

Ausencias 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:read

Request

{
  "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

schedule.publishedtime_entry.validatedabsence.approvedabsence.rejectedpayroll.hours_exportpayroll.absences_export
{
  "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"
  }
}
HeaderDescripcion
x-oktavia-eventTipo de evento enviado por Oktavia.
x-oktavia-signatureFirma HMAC SHA-256 calculada con el secret de la conexion.
x-oktavia-timestampTimestamp usado para firmar el payload.
x-oktavia-delivery-idIdentificador 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.

pos:daily-close:writepos:sales:writepos:products:writereservations:forecast:writecustom:events:writepayroll:hours:readpayroll:absences:readwebhooks:receive

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.

Abrir Postman

Antes de enviar

  1. 1. El cliente crea una conexion sandbox en Oktavia Connect.
  2. 2. Oktavia genera `connectionId`, API key sandbox y secret sandbox.
  3. 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
No pegues credenciales productivas en equipos compartidos.

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.