Referencia de API
Todo lo que expone el backend cuelga del prefijo /api, fijado en
backend/src/main.ts.
Esta tabla no está escrita a mano: se lee de los decoradores @Controller y @Get/@Post/… de
cada controlador cada vez que se construye el sitio. Si añades un endpoint, aparece aquí solo.
La columna «Qué hace» sale del comentario JSDoc del método. Documentar un endpoint es comentarlo donde se implementa:
/** Devuelve los huecos libres de un servicio en un rango de fechas. */
@Get('slots')
async getSlots(@Query() query: SlotsQuery) { ... }
La especificación OpenAPI
El mismo inventario se publica como openapi.json, en OpenAPI 3.1.
Sirve para importar todos los endpoints en Postman o Insomnia de una vez.
No lleva esquemas de cuerpo ni de respuesta, y es una limitación honesta: el backend no usa
class-validator ni decoradores de Swagger, así que no hay de dónde inferirlos sin
inventárselos. Lleva las rutas, los métodos, los parámetros de ruta y los guards de cada uno.
Sobre la autenticación
El backend no autentica globalmente las peticiones HTTP: no hay un guard global en
main.ts. La protección es por endpoint, con los guards que aparecen en la columna
correspondiente (SuperadminGuard, PermissionGuard, ModuleGuard, SandboxModeGuard).
Un endpoint sin guards es accesible por cualquiera que alcance el backend. En algunos casos es deliberado —los webhooks entrantes y el widget de chat web tienen que serlo, y se validan por firma o por token propio— pero conviene mirar dos veces antes de dar por hecho que algo está protegido.
Los orígenes permitidos para el navegador se controlan con CORS_ORIGINS, salvo para las rutas
públicas del widget (/api/webhooks/webchat y /api/bots/message), que aceptan cualquier origen
porque el widget se incrusta en webs de clientes.
Todos los endpoints
backend/src/**/*.controller.ts al construir el sitio. No se edita a mano: se actualiza con yarn gen en docs/.| Método | Ruta | Qué hace | Guards | Código |
|---|---|---|---|---|
| GET | /api | sin describir | ninguno | App |
| POST | /api/admin/data-sync | sin describir | SuperadminGuard | DataSync |
| GET | /api/admin/data-sync/status | sin describir | SuperadminGuard | DataSync |
| GET | /api/admin/data-sync/tenants | sin describir | SuperadminGuard | DataSync |
| GET | /api/admin/platform-settings | sin describir | SuperadminGuard | PlatformSettings |
| PUT | /api/admin/platform-settings/:key | sin describir | SuperadminGuard | PlatformSettings |
| GET | /api/admin/sandbox-channels | sin describir | SandboxModeGuardSuperadminGuard | SandboxChannels |
| PUT | /api/admin/sandbox-channels/:channelCode | sin describir | SandboxModeGuardSuperadminGuard | SandboxChannels |
| GET | /api/admin/sandbox-channels/leases | sin describir | SandboxModeGuardSuperadminGuard | SandboxChannels |
| DELETE | /api/admin/sandbox-channels/leases/:channelCode | sin describir | SandboxModeGuardSuperadminGuard | SandboxChannels |
| POST | /api/admin/sandbox-channels/leases/:channelCode | sin describir | SandboxModeGuardSuperadminGuard | SandboxChannels |
| GET | /api/admin/sandbox-channels/whatsapp/webhook | A dónde entrega Meta el número de WhatsApp del sandbox: Test (override) o producción. | SandboxModeGuardSuperadminGuard | SandboxChannels |
| PUT | /api/admin/sandbox-channels/whatsapp/webhook | Mueve la entrega del número: `produccion` quita el override para usarlo en producción; `test` lo vuelve a poner. La URL de Test sale del entorno, nunca del cuerpo: el cliente solo elige el destino. | SandboxModeGuardSuperadminGuard | SandboxChannels |
| POST | /api/billing/rollup | Dispara el rollup diario de consumo hacia Odoo. Lo llama un ir.cron de Odoo (diario) con el secreto compartido. Idempotente/acumulativo. | ninguno | Billing |
| POST | /api/billing/sync | Backfill completo bajo demanda (uso operativo). Protegido por el mismo secreto del webhook, enviado como `Authorization: Bearer <secret>`. | ninguno | Billing |
| POST | /api/billing/tenant-subscription | Alta/cambio de la suscripción de un tenant (lo invoca la server-action del superadmin, que además valida is_superadmin del lado de Supabase). Escribe en Odoo y refresca el espejo. Protegido por el secreto compartido. | ninguno | Billing |
| POST | /api/billing/webhook/odoo | Recibe el aviso de Odoo de que un plan/suscripción cambió. El body solo dice qué cambió; el dato real se re-consulta a Odoo (ver BillingSyncService). | ninguno | Billing |
| POST | /api/bot-safety/:botId/decision | sin describir | PermissionGuard | BotSafety |
| POST | /api/bot-safety/:botId/review | Revisión a demanda desde el panel del tenant (tras editar el bot). | PermissionGuard | BotSafety |
| GET | /api/bot-safety/queue | sin describir | PermissionGuard | BotSafety |
| POST | /api/bot-safety/tenants/:tenantId/verify | Quita los límites de cuenta nueva a un tenant (ver TenantTrustService). | PermissionGuard | BotSafety |
| GET | /api/bots/:botId/flow-versions | sin describir | PermissionGuard | FlowVersions |
| POST | /api/bots/:botId/flow-versions | sin describir | PermissionGuard | FlowVersions |
| DELETE | /api/bots/:botId/flow-versions/:versionId | sin describir | PermissionGuard | FlowVersions |
| GET | /api/bots/:botId/flow-versions/:versionId | sin describir | PermissionGuard | FlowVersions |
| POST | /api/bots/:botId/flow-versions/:versionId/activate | sin describir | PermissionGuard | FlowVersions |
| GET | /api/bots/agent-tools | Static manifest of all tools the flow editor can offer in the "Herramientas del agente" picker on LLM nodes. Per-bot runtime availability (module enabled, tools_config, indexed records…) is enforced server-side at agent invocation time, so this list is intentionally global. Every service a factory might need must be passed here. A factory whose dependency is missing returns null and its tool silently disappears from the picker — which is how the scheduling and catalog tools were invisible even though they worked at runtime. | PermissionGuard | Bots |
| POST | /api/bots/approvals/:id/continue | sin describir | PermissionGuard | Approvals |
| GET | /api/bots/conversations/:conversationId/state | Dónde está la conversación y por qué pasos pasó. Solo estructura, sin PHI. | PermissionGuard | ConversationState |
| GET | /api/bots/conversations/:conversationId/state/history | Puntos de guardado de la conversación (uno por mensaje). Solo estructura. | PermissionGuard | ConversationState |
| POST | /api/bots/conversations/:conversationId/state/replay | Reproduce EN SECO un mensaje desde un punto de guardado: devuelve el recorrido que haría hoy el flujo, sin enviar nada ni tocar la conversación. Es una herramienta de depuración, por eso pide bot.update. | PermissionGuard | ConversationState |
| POST | /api/bots/conversations/:conversationId/state/reset | Olvida la memoria del bot en esta conversación (el próximo mensaje empieza de cero). | PermissionGuard | ConversationState |
| POST | /api/bots/dashboards/generate | sin describir | ninguno | Dashboards |
| POST | /api/bots/dashboards/sessions | sin describir | ninguno | Dashboards |
| GET | /api/bots/dashboards/sessions/:sessionId | sin describir | ninguno | Dashboards |
| POST | /api/bots/dashboards/sessions/:sessionId/files | sin describir | ninguno | Dashboards |
| POST | /api/bots/dashboards/sessions/:sessionId/message | sin describir | ninguno | Dashboards |
| POST | /api/bots/message | sin describir | PermissionGuard | Bots |
| POST | /api/bots/reload | sin describir | PermissionGuard | Bots |
| GET | /api/bots/tenants | Qué tenants tiene cargados el registro: dato de operación, solo superadmin. | PermissionGuard | Bots |
| GET | /api/bots/tenants/:tenantId | sin describir | PermissionGuard | Bots |
| POST | /api/channels/email/credentials | sin describir | PermissionGuard | EmailCredentials |
| GET | /api/channels/email/credentials/status | sin describir | PermissionGuard | EmailCredentials |
| POST | /api/channels/email/test-connection | sin describir | PermissionGuard | EmailCredentials |
| GET | /api/copilot/access | sin describir | CopilotGuard | Copilot |
| POST | /api/copilot/message | sin describir | CopilotGuard | Copilot |
| GET | /api/copilot/ping | Utilidad para el guard: tenant_id también puede ir por query en GET. | CopilotGuard | Copilot |
| GET | /api/copilot/threads | sin describir | CopilotGuard | Copilot |
| GET | /api/copilot/threads/:id | sin describir | CopilotGuard | Copilot |
| POST | /api/crm/products/:id/embedding/enqueue | Encola la regeneración del embedding (BullMQ, async, recomendado). | ninguno | Embeddings |
| POST | /api/crm/products/:id/embedding/regenerate-now | Regenera el embedding ahora mismo (síncrono). Útil para QA, para fix puntuales, o cuando Redis/BullMQ no está disponible. Bloquea el request unos cientos de ms (call a OpenAI). | ninguno | Embeddings |
| POST | /api/crm/products/embeddings/enqueue-pending | Encola en masa los productos pendientes del tenant/workspace. | ninguno | Embeddings |
| POST | /api/crm/products/search-semantic | Búsqueda semántica multi-industria. | ninguno | Embeddings |
| GET | /api/data-sources | sin describir | ninguno | DataSources |
| DELETE | /api/data-sources/:id | sin describir | ninguno | DataSources |
| GET | /api/data-sources/:id | sin describir | ninguno | DataSources |
| PATCH | /api/data-sources/:id | sin describir | ninguno | DataSources |
| DELETE | /api/data-sources/:id/node-attach | sin describir | ninguno | DataSources |
| POST | /api/data-sources/:id/node-attach | sin describir | ninguno | DataSources |
| POST | /api/data-sources/:id/reindex | sin describir | ninguno | DataSources |
| GET | /api/data-sources/:id/signed-url | sin describir | ninguno | DataSources |
| POST | /api/data-sources/api | sin describir | ninguno | DataSources |
| POST | /api/data-sources/document | sin describir | ninguno | DataSources |
| POST | /api/data-sources/rows | sin describir | ninguno | DataSources |
| POST | /api/errors/report | sin describir | ninguno | ErrorReporting |
| GET | /api/flow-assistant/access | sin describir | FlowAssistantGuard | FlowAssistant |
| POST | /api/flow-assistant/message | sin describir | FlowAssistantGuard | FlowAssistant |
| POST | /api/inbox/deliver-media | sin describir | ninguno | Inbox |
| POST | /api/instagram/send-text | sin describir | ninguno | |
| GET | /api/invoicing/invoices | sin describir | ModuleGuardPermissionGuard | Invoicing |
| POST | /api/invoicing/invoices | sin describir | ModuleGuardPermissionGuard | Invoicing |
| GET | /api/invoicing/invoices/:engineId | sin describir | ModuleGuardPermissionGuard | Invoicing |
| GET | /api/invoicing/invoices/:engineId/ride | sin describir | ModuleGuardPermissionGuard | Invoicing |
| POST | /api/invoicing/invoices/sync | Consulta al motor las facturas pendientes de este tenant. La pantalla lo pide al abrirse, para no mostrar "Pendiente" lo que el SRI ya autorizó. | ModuleGuardPermissionGuard | Invoicing |
| GET | /api/invoicing/issuers | Lectura con el permiso de consulta: quien emite necesita elegir emisor, y el listado no lleva nada secreto —el certificado vive solo en el motor—. | ModuleGuardPermissionGuard | Invoicing |
| POST | /api/invoicing/issuers | sin describir | ModuleGuardPermissionGuard | Invoicing |
| DELETE | /api/invoicing/issuers/:issuerId | Desactiva el emisor. En el motor no se borra nada: las facturas se conservan. | ModuleGuardPermissionGuard | Invoicing |
| PATCH | /api/invoicing/issuers/:issuerId | Editar un emisor o cambiarle el certificado. Ver `InvoicingService.updateIssuer`. | ModuleGuardPermissionGuard | Invoicing |
| GET | /api/invoicing/status | Si el plan incluye la facturación. La pantalla lo pregunta antes de pintar nada. | ModuleGuardPermissionGuard | Invoicing |
| POST | /api/invoicing/webhook/engine | sin describir | ninguno | InvoicingWebhook |
| GET | /api/kiosk/admin/config | sin describir | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/config | sin describir | ModuleGuardPermissionGuard | KioskAdmin |
| GET | /api/kiosk/admin/devices | sin describir | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/devices/:id/pair | Vincula ese código a un dispositivo EXISTENTE: se cambió el PC de recepción o se reinstaló Windows. En cuanto la máquina nueva recoge su credencial, la de la vieja deja de valer. | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/devices/:id/revoke | sin describir | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/devices/claim | Vincula la pantalla que muestra ese código creando un dispositivo nuevo. El alta y la vinculación van juntas a propósito: un dispositivo que existe en el panel pero no en ninguna máquina es un estado que solo sirve para confundir. Si el código no vale, no se crea nada. | ModuleGuardPermissionGuard | KioskAdmin |
| GET | /api/kiosk/admin/tickets | sin describir | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/tickets/call | Llamar al siguiente. Es lo que hace que la pantalla de la sala cambie. | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/tickets/close | sin describir | ModuleGuardPermissionGuard | KioskAdmin |
| POST | /api/kiosk/admin/tickets/start | El paciente entró a consulta. Avanza las DOS cosas: la cita a `in_progress` y el turno a cerrado/atendido. El cambio de estado de la cita va por `SchedulingService.updateStatus` y no por un UPDATE propio — los efectos secundarios de una cita (recordatorios, eventos de dominio, validación de la transición) tienen un solo dueño. | ModuleGuardPermissionGuard | KioskAdmin |
| GET | /api/kiosk/board | La pizarra de la sala de espera. Solo para dispositivos de tipo `display`: el token de una TV colgada de una pared no puede poder preguntar por cédulas. | KioskGuardModuleGuard | KioskDevice |
| POST | /api/kiosk/checkin | Registra la llegada y emite el turno. El vale viene de un `lookup` previo. | KioskGuardModuleGuard | KioskDevice |
| POST | /api/kiosk/lookup | Busca por documento. Devuelve lo MISMO para un documento desconocido y para uno conocido sin cita hoy: distinguirlos convertiría el kiosko en un oráculo de padrón. Ver el comentario de `KioskService.lookup`. | KioskGuardModuleGuard | KioskDevice |
| POST | /api/kiosk/pair/poll | ¿Ya me reclamaron? La credencial se entrega UNA vez, en la respuesta que encuentra la vinculación hecha. El vale va en el cuerpo y no en la URL: en la URL acabaría en los logs de acceso de cualquier proxy por el que pase. | ninguno | KioskDevice |
| POST | /api/kiosk/pair/start | Una máquina sin vincular pide un código para mostrarlo. Sin guard: todavía no tiene credencial, y conseguir una es justo lo que viene a hacer. No revela nada ni crea nada que pertenezca a un tenant; lo único que se lleva es un código y un vale que no sirven hasta que alguien con permiso reclama la pantalla desde el panel. | ninguno | KioskDevice |
| POST | /api/kiosk/printed | Telemetría de impresión. Registra el INTENTO, no que saliera papel. | KioskGuardModuleGuard | KioskDevice |
| GET | /api/kiosk/session | Con qué trabajar: quién es esta máquina, qué documentos pide su país y —lo importante— QUÉ HORA ES. El kiosko no usa su propio reloj en ninguna decisión. Un PC de vestíbulo sin NTP se desfasa, y un reloj adelantado dejaría a todo el mundo fuera de la ventana de check-in sin que nadie entendiera por qué. | KioskGuardModuleGuard | KioskDevice |
| POST | /api/kiosk/walk-in | Turno para quien llega sin cita. NO crea una cita. | KioskGuardModuleGuard | KioskDevice |
| POST | /api/messenger/send-text | sin describir | ninguno | Messenger |
| GET | /api/modules/:tenantId | Catálogo completo con el estado del tenant y sus dependencias resueltas. | PermissionGuard | Modules |
| GET | /api/modules/:tenantId/enabled | Solo los códigos activos. Barato de llamar en cada arranque de sesión. | PermissionGuard | Modules |
| POST | /api/modules/toggle | Activa o desactiva un módulo. Desactivar NUNCA borra datos: marca enabled=false y sella disabled_at, de modo que reactivar devuelve todo intacto. | PermissionGuard | Modules |
| POST | /api/onboarding/assistant | sin describir | PermissionGuard | Onboarding |
| POST | /api/onboarding/business | sin describir | PermissionGuard | Onboarding |
| POST | /api/onboarding/channel | sin describir | PermissionGuard | Onboarding |
| POST | /api/onboarding/complete | sin describir | PermissionGuard | Onboarding |
| GET | /api/onboarding/packs | sin describir | PermissionGuard | Onboarding |
| GET | /api/onboarding/packs/public | Listado de packs sin exigir membership — para el alta de tenant (superadmin). | PermissionGuard | Onboarding |
| POST | /api/onboarding/preseed | Pre-siembra desde superadmin al crear el tenant. | PermissionGuard | Onboarding |
| POST | /api/onboarding/preview-chat | sin describir | PermissionGuard | Onboarding |
| POST | /api/onboarding/prompt-draft | sin describir | PermissionGuard | Onboarding |
| POST | /api/onboarding/skip | sin describir | PermissionGuard | Onboarding |
| GET | /api/onboarding/state | sin describir | PermissionGuard | Onboarding |
| GET | /api/onboarding/user-state | sin describir | PermissionGuard | Onboarding |
| POST | /api/onboarding/user-state | sin describir | PermissionGuard | Onboarding |
| GET | /api/payments/history | sin describir | PaymentsEnabledGuard | Payments |
| GET | /api/payments/links | sin describir | PaymentsEnabledGuard | Payments |
| POST | /api/payments/links | sin describir | PaymentsEnabledGuard | Payments |
| POST | /api/payments/links/:id/disable | sin describir | PaymentsEnabledGuard | Payments |
| POST | /api/payments/sessions | Crea sesión Checkout vía Odoo (create_pay_session). Protegido por el mismo secreto Odoo (Bearer) — lo invocan server actions. | PaymentsEnabledGuard | Payments |
| GET | /api/payments/sessions/:reference | sin describir | PaymentsEnabledGuard | Payments |
| GET | /api/sandbox-channels | sin describir | SandboxModeGuardAuthenticatedGuard | SandboxChannelsTenant |
| DELETE | /api/sandbox-channels/leases/:channelCode | sin describir | SandboxModeGuardAuthenticatedGuard | SandboxChannelsTenant |
| POST | /api/sandbox-channels/leases/:channelCode | sin describir | SandboxModeGuardAuthenticatedGuard | SandboxChannelsTenant |
| GET | /api/scheduling/appointments | Citas de un rango con los nombres resueltos. Alimenta el calendario. | ModuleGuard | Scheduling |
| POST | /api/scheduling/appointments | sin describir | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/cancel | sin describir | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/contact | Asignar o quitar el paciente de una cita existente. | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/offer-reschedule | Cancela cada cita listada y le ofrece al paciente reagendar por WhatsApp. Se llama desde la alerta de conflicto al guardar un bloqueo de agenda. El body solo trae `resource_id` (no un `appointment_id` suelto): con eso `AppointmentWriteGuard` toma la vía "alta" y comprueba que quien llama sea dueño de ESE recurso, que es exactamente lo que hace falta —todas las citas de la lista son, por construcción, de ese mismo recurso—. Las citas se recargan de la base por id: no se confía en los datos que mande el cliente. | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/reschedule | sin describir | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/send-reminder | Envía ya el recordatorio de una cita, a mano. Sale por el mismo canal por el que se reservó (la conversación de origen decide la ruta). Lleva `AppointmentWriteGuard`: avisar a un paciente es actuar sobre su cita, y el guard saca el tenant de la fila real y exige `manage` (con alcance propio si no hay `view_all`). | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/status | Confirmar, completar, marcar ausencia o reabrir. | ModuleGuardAppointmentWriteGuard | Scheduling |
| POST | /api/scheduling/appointments/substatus | Poner o quitar el sub-estado de una cita (etiqueta informativa). Mismo guard que el estado: quien no puede tocar esa agenda, tampoco etiqueta. | ModuleGuardAppointmentWriteGuard | Scheduling |
| GET | /api/scheduling/config/:entity | Lista entidades de configuración del tenant. Query opcionales: `resource_id`, `location_id` (eq). Para `availabilityExceptions` también `from`/`to` (solape) y `resource_ids` (lista separada por comas) — una sola petición para el calendario. | ModuleGuardPermissionGuard | SchedulingConfig |
| POST | /api/scheduling/config/:entity | sin describir | ModuleGuardPermissionGuardSchedulingWriteGuard | SchedulingConfig |
| DELETE | /api/scheduling/config/:entity/:id | sin describir | ModuleGuardPermissionGuardSchedulingWriteGuard | SchedulingConfig |
| PATCH | /api/scheduling/config/:entity/:id | sin describir | ModuleGuardPermissionGuardSchedulingWriteGuard | SchedulingConfig |
| GET | /api/scheduling/config/availability-exceptions/conflicts | Citas que chocarían con un bloqueo de agenda antes de guardarlo. Ruta de dos segmentos (`availability-exceptions/conflicts`), así que no colisiona con el comodín `:entity` de una sola palabra — pero se declara aquí arriba igualmente, junto al resto de rutas específicas, por consistencia con ellas. | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/block-reschedule-offer | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/block-reschedule-offer | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/calendar-view | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/calendar-view | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/linkable-users | Usuarios vinculables a un recurso. Va antes de :entity para no colisionar. | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/reminders | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/reminders | Cambiar cuándo se avisa a los pacientes es configuración de la sede, no mantenimiento de la ficha de un profesional: exige el permiso completo, no la vía "propio" de SchedulingWriteGuard. | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/reminders/cold-outreach | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/reminders/outreach | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| POST | /api/scheduling/config/reminders/whatsapp-template | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/reminders/whatsapp-template | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/reminders/whatsapp-template/candidates | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| POST | /api/scheduling/config/reminders/whatsapp-template/refresh | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/resources/:id/services | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| POST | /api/scheduling/config/resources/:id/services | sin describir | ModuleGuardPermissionGuardSchedulingWriteGuard | SchedulingConfig |
| GET | /api/scheduling/config/services/:id/locations | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| POST | /api/scheduling/config/services/:id/locations | sin describir | ModuleGuardPermissionGuardSchedulingWriteGuard | SchedulingConfig |
| GET | /api/scheduling/config/status-colors | Color de cada estado de cita. Lo lee cualquiera del tenant: se pinta en todas las vistas. | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/status-colors | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/substatuses | Sub-estados de cita (etiquetas con color encima del estado). Los lee cualquiera del tenant: se pintan en calendario, citas y hoy. | ModuleGuardPermissionGuard | SchedulingConfig |
| PUT | /api/scheduling/config/substatuses | sin describir | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/config/substatuses/usage | Uso por sub-estado y estado: solo para quien configura (avisa antes de romper). | ModuleGuardPermissionGuard | SchedulingConfig |
| GET | /api/scheduling/contacts/:contactId/appointments | sin describir | ModuleGuard | Scheduling |
| GET | /api/scheduling/slots | Huecos disponibles. `location_id` es opcional a propósito: sin él busca en todas las sedes y cada hueco viene etiquetado con la suya. | ModuleGuard | Scheduling |
| GET | /api/subflows | sin describir | PermissionGuard | Subflows |
| POST | /api/subflows | sin describir | PermissionGuard | Subflows |
| DELETE | /api/subflows/:id | sin describir | PermissionGuard | Subflows |
| GET | /api/subflows/:id | sin describir | PermissionGuard | Subflows |
| PATCH | /api/subflows/:id | sin describir | PermissionGuard | Subflows |
| GET | /api/subflows/:id/usages | sin describir | PermissionGuard | Subflows |
| GET | /api/subflows/:id/versions | sin describir | PermissionGuard | Subflows |
| POST | /api/subflows/:id/versions | sin describir | PermissionGuard | Subflows |
| GET | /api/subflows/:id/versions/:versionId | sin describir | PermissionGuard | Subflows |
| GET | /api/webhook/whatsapp | sin describir | ninguno | WhatsAppWebhook |
| POST | /api/webhook/whatsapp | sin describir | ninguno | WhatsAppWebhook |
| POST | /api/webhooks/email | sin describir | ninguno | |
| GET | /api/webhooks/meta | sin describir | PermissionGuard | Meta |
| POST | /api/webhooks/meta | sin describir | PermissionGuard | Meta |
| POST | /api/webhooks/meta/embedded-signup-token | Exchange Embedded Signup authorization code for access token. Body: { code: string, redirect_uri?: string } (redirect_uri can be "" when using JS SDK). | PermissionGuard | Meta |
| GET | /api/webhooks/meta/fb-pages | Fetch Facebook Pages the user manages. Used in Messenger and Instagram wizard Step 2. Query: access_token | PermissionGuard | Meta |
| GET | /api/webhooks/meta/ig-account | Fetch the Instagram Business Account linked to a Facebook Page. Used in Instagram wizard Step 2. Query: page_id, access_token | PermissionGuard | Meta |
| POST | /api/webhooks/meta/phone-numbers | Fetch phone numbers for a WABA after Embedded Signup. Body: { access_token: string (required), waba_id?: string (optional — if omitted, resolves first assigned WABA) } Token is sent in the request body to avoid exposure in server logs / browser history. | PermissionGuard | Meta |
| POST | /api/webhooks/telegram/:channelAccountId | Telegram sends POST updates to this URL | ninguno | Telegram |
| POST | /api/webhooks/telegram/set-webhook | Register webhook for a bot token | ninguno | Telegram |
| GET | /api/webhooks/telegram/validate-token | Validate bot token and return bot info | ninguno | Telegram |
| POST | /api/webhooks/webchat | sin describir | ninguno | Webchat |
| GET | /api/webhooks/webchat/config/:channelAccountId | Public bootstrap config for the embeddable widget — called from any website. | ninguno | Webchat |
| POST | /api/webhooks/x | sin describir | ninguno | X |
| POST | /api/whatsapp/onboarding/complete | sin describir | PermissionGuard | WhatsAppOnboarding |
| POST | /api/whatsapp/onboarding/select-number | Cuando la WABA tenía varios números y el usuario eligió uno. | PermissionGuard | WhatsAppOnboarding |
| POST | /api/whatsapp/onboarding/sync | Reintenta la sincronización de contactos/historial (solo dentro de 24 h). | PermissionGuard | WhatsAppOnboarding |
| POST | /api/whatsapp/send-text | sin describir | PermissionGuard | |
| GET | /api/whatsapp/templates | Approved message templates (including FLOW) from the WABA linked to this tenant/bot. | PermissionGuard | |
| GET | /api/whatsapp/xenpia-numbers | Returns the phone numbers registered in a Xenpia-owned WABA. Uses WHATSAPP_ACCESS_TOKEN. Optional `waba_id` selects which owned WABA to list; defaults to WHATSAPP_WABA_ID. | PermissionGuard | |
| POST | /api/whatsapp/xenpia-numbers | Add a phone number to a specific WABA (client's own WABA under Xenpia's BM). Body: { waba_id, phone_number, country_code, verified_name } Next step: call /xenpia-numbers/request-otp to send verification code. | PermissionGuard | |
| POST | /api/whatsapp/xenpia-numbers/register | Register a Xenpia-owned number on the Cloud API so it can send/receive. This is the activation step that follows OTP verification: verifying the OTP only proves ownership, while `/register` enables the number on the Cloud API and sets its two-step-verification PIN. Body: { phone_number_id, pin } — pin is a 6-digit code chosen for the number. An "already registered" response is treated as success so retries are safe. | PermissionGuard | |
| POST | /api/whatsapp/xenpia-numbers/request-otp | Send OTP (SMS or voice) to a phone number registered in Xenpia's WABA. Body: { phone_number_id, method: 'SMS' | 'VOICE', language? } | PermissionGuard | |
| GET | /api/whatsapp/xenpia-numbers/status | Inspect a Xenpia-owned number and report the single next step needed before it can send/receive on the Cloud API: 'verify' (OTP), 'register', or 'done'. Used by the "número existente" flow for numbers created in the Meta panel. Query: ?phone_number_id=... | PermissionGuard | |
| POST | /api/whatsapp/xenpia-numbers/verify-otp | Verify OTP for a phone number in Xenpia's WABA. Body: { phone_number_id, code } On success the number is active and ready to use. | PermissionGuard | |
| POST | /api/whatsapp/xenpia-waba | Create a new WABA under Xenpia's Business Manager for a specific client/tenant. Then subscribes Xenpia's app to the new WABA. Body: { waba_name, currency?, timezone_id? } Returns: { ok, waba_id } | PermissionGuard | |
| GET | /api/whatsapp/xenpia-waba/:tenantId | Check if a tenant already has a WABA under Xenpia's BM. Returns { ok, waba_id, waba_name } — waba_id is null if none found. | PermissionGuard | |
| GET | /api/whatsapp/xenpia-wabas | Lists WhatsApp Business Accounts owned by Xenpia's Business Manager. Used in the "Xenpia-owned number" wizard: pick a WABA, then list its phones. | PermissionGuard |
200 endpoints.