Integraciones
API REST v1
La API REST de Citeri para leer y escribir en la agenda de un negocio: citas, huecos libres, clientas, catálogo y cobros. JSON, con errores con código, paginación por cursor e idempotencia.
La referencia completa está en OpenAPI 3.1 y puedes probar cada operación en el explorador del portal.
Claves#
Crea una cuenta en el portal de desarrolladores. Cada equipo tiene un negocio de pruebas con datos ficticios que no sale en el buscador, no se factura y no avisa a nadie.
| Clave | Ve |
|---|---|
ctk_test_… | Solo tu negocio de pruebas |
ctk_live_… | Los negocios que han conectado una app de tu equipo con Entrar con Citeri. Indica cuál con la cabecera Citeri-Org: <org_id>. Puede hacer lo que permitan a la vez la clave y lo que el negocio concedió. |
curl https://citeri.es/api/v1/appointments?from=2026-11-03 \
-H "Authorization: Bearer ctk_live_…" \
-H "Citeri-Org: 5f0c…"
Las claves llevan permisos (los mismos scopes que OAuth), pueden caducar, limitarse a unas IPs y rotarse con periodo de gracia: la vieja sigue valiendo hasta la hora que elijas. También vale un token OAuth de «Entrar con Citeri» en lugar de una clave.
Operaciones#
| Operación | Permiso |
|---|---|
GET /api/v1/organization | — |
GET /api/v1/services, GET /api/v1/employees | catalogo:leer |
GET /api/v1/availability?service_id=&date= | citas:leer |
GET /api/v1/appointments, GET /api/v1/appointments/{id} | citas:leer |
POST /api/v1/appointments, …/{id}/cancel, …/{id}/reschedule | citas:escribir |
GET /api/v1/clients, GET /api/v1/clients/{id} | clientas:leer (el teléfono, con clientas:telefono) |
POST /api/v1/clients, PATCH /api/v1/clients/{id} | clientas:escribir |
GET /api/v1/payments | finanzas |
Crear o mover una cita pasa por las mismas reglas que la reserva online: horario, solapes, servicios de cada profesional y plazo de cancelación del negocio. Con notify (por defecto true) la clienta recibe el aviso como si lo hiciera el salón.
Listas y paginación#
{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "eyJz…" }
Pide la siguiente página con ?cursor=<next_cursor>. limit va de 1 a 100 (20 por defecto).
Idempotencia#
Manda Idempotency-Key: <algo único> en los POST. Si repites la petición con la misma clave en 24 h, recibes la respuesta original (con Idempotent-Replayed: true) en vez de crear otra cita. Con la misma clave y otro cuerpo: 422 idempotency_key_reused.
Errores y límites#
{ "error": { "code": "insufficient_scope", "permission": "finance.manage", "message": "La aplicación no tiene permiso para esta función" } }
| Código | Qué pasa |
|---|---|
401 invalid_api_key | La clave no existe, está revocada o caducada |
403 insufficient_scope | Falta un permiso |
403 ip_not_allowed | La clave no se puede usar desde esa IP |
403 test_key_live_org / live_key_sandbox | Clave de pruebas contra un negocio real, o al revés |
400 org_required, 403 org_not_connected | Con ctk_live_: falta Citeri-Org, o ese negocio no conectó tu app |
429 rate_limited | 100 peticiones/min por clave de pruebas y 300 por clave real. Mira RateLimit-Remaining y Retry-After |
Cada respuesta lleva Citeri-Request-Id: búscalo en Registros para ver la petición, o dánoslo si escribes a soporte.
Para enterarte de los cambios sin preguntar cada rato, usa webhooks.