{"openapi": "3.1.2", "info": {"title": "FunnelChat Conversations", "version": "0.0.1", "description": "Public API of Funnelchat Conversations. Authenticate every request with `Authorization: Bearer <id>|fc_live_...`. Each operation shows the permission (`conversations:read`, `conversations:write` or `conversations:send`) your key needs.\n\n## Webhooks\n\nLos webhooks avisan a un sistema externo, por HTTP, cuando algo pasa en tu cuenta, sin que tengas que consultar la API cada tanto. Registrás una URL HTTPS, elegís los tipos de evento que querés recibir y Funnelchat envía a esa URL un `POST` firmado cada vez que ocurre uno. Las rutas de administración requieren una clave de API y que la use el titular de la cuenta.\n\n### Cómo suscribirse\n\nEstas son las nueve rutas para administrar suscripciones:\n\n| Ruta | Para qué sirve | Permiso |\n| --- | --- | --- |\n| `GET /api/v1/webhooks` | Listar las suscripciones | `conversations:read` |\n| `POST /api/v1/webhooks` | Crear una suscripción | `conversations:write` |\n| `GET /api/v1/webhooks/events` | Ver el catálogo de tipos de evento | `conversations:read` |\n| `GET /api/v1/webhooks/{webhook}` | Ver una suscripción | `conversations:read` |\n| `PUT /api/v1/webhooks/{webhook}` | Cambiar URL, tipos o estado activo | `conversations:write` |\n| `DELETE /api/v1/webhooks/{webhook}` | Eliminar una suscripción | `conversations:write` |\n| `POST /api/v1/webhooks/{webhook}/rotate-secret` | Generar un secreto nuevo | `conversations:write` |\n| `POST /api/v1/webhooks/{webhook}/test` | Enviar ahora un evento de prueba | `conversations:write` |\n| `GET /api/v1/webhooks/{webhook}/deliveries` | Ver el historial de entregas | `conversations:read` |\n\nEjemplo de alta:\n\n```bash\ncurl -X POST \"https://TU-HOST/api/v1/webhooks\" \\\n  -H \"Authorization: Bearer <id>|fc_live_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"url\": \"https://example.com/hooks/funnelchat\",\n    \"description\": \"Mi integración\",\n    \"events\": [\"message.received\"]\n  }'\n```\n\nRespuesta `201`:\n\n```json\n{\n  \"data\": {\n    \"uuid\": \"00000000-0000-4000-8000-000000000001\",\n    \"url\": \"https://example.com/hooks/funnelchat\",\n    \"description\": \"Mi integración\",\n    \"events\": [\"message.received\"],\n    \"active\": true,\n    \"inactive_reason\": null,\n    \"created_at\": \"2026-10-01T12:00:00+00:00\",\n    \"updated_at\": \"2026-10-01T12:00:00+00:00\",\n    \"secret\": \"<secreto de firma>\"\n  }\n}\n```\n\nEl `secret` se muestra **una sola vez**, en esta respuesta (y al rotarlo). Guardalo: no se puede volver a consultar. En `events` podés usar los tipos `message.received`, `flow.completed`, `broadcast.finished`, `contact.stage_changed`, `message.status_changed`, `conversation.closed`, `conversation.assigned`, `contact.tag_added`, `broadcast.paused`, `contact.tag_removed`, `contact.created`, `template.status_changed`, `flow.failed`, `whatsapp_form.completed` o `*` para todos los demás que se puedan suscribir (`message.status_changed` siempre se suscribe de forma explícita: `*` no lo incluye). La URL debe ser `https` y apuntar a un destino público.\n\n### El sobre\n\nCada entrega es un `POST` con un cuerpo JSON con esta forma. El contenido de `data` depende del tipo de evento (ver el catálogo más abajo).\n\n| Campo | Descripción |\n| --- | --- |\n| `id` | Identificador único del evento (`evt_...`). Es el mismo en todos los reintentos. |\n| `type` | Tipo de evento, por ejemplo `message.received`. |\n| `version` | Versión del formato del evento (hoy `1`). |\n| `occurred_at` | Momento en que ocurrió, en UTC (ISO 8601). |\n| `data` | Datos del evento. |\n\n### Cabeceras\n\n| Cabecera | Contenido |\n| --- | --- |\n| `Content-Type` | `application/json` |\n| `X-Funnelchat-Signature` | Firma de la entrega, con la forma `t=<timestamp>,v1=<firma>` |\n| `X-Funnelchat-Event` | Tipo de evento (igual que `type` en el cuerpo) |\n| `X-Funnelchat-Delivery` | Identificador de esta entrega (cambia en cada intento) |\n\n### Cómo verificar la firma\n\nCada entrega lleva la cabecera `X-Funnelchat-Signature` con la forma `t=<timestamp>,v1=<firma>`. Para verificarla:\n\n1. Tomá el **cuerpo crudo** de la petición, tal como llegó, sin volver a codificar el JSON.\n2. Armá el texto `t + \".\" + cuerpo` (el timestamp, un punto y el cuerpo).\n3. Calculá su HMAC-SHA256 con el secreto de la suscripción y comparalo, en tiempo constante, con `v1`.\n4. Rechazá la entrega si `t` se aleja del reloj de tu servidor más de 300 segundos.\n\nEjemplo en PHP:\n\n```php\nfunction verificarFirma(string $cuerpoCrudo, string $cabecera, string $secreto, int $tolerancia = 300): bool\n{\n    parse_str(str_replace(',', '&', $cabecera), $partes);\n\n    if (! isset($partes['t'], $partes['v1']) || ! ctype_digit($partes['t'])) {\n        return false;\n    }\n\n    if (abs(time() - (int) $partes['t']) > $tolerancia) {\n        return false;\n    }\n\n    $esperada = hash_hmac('sha256', $partes['t'].'.'.$cuerpoCrudo, $secreto);\n\n    return hash_equals($esperada, $partes['v1']);\n}\n```\n\nEjemplo en JavaScript (Node.js):\n\n```javascript\nconst crypto = require('crypto');\n\nfunction verificarFirma(cuerpoCrudo, cabecera, secreto, tolerancia = 300) {\n  const partes = Object.fromEntries(cabecera.split(',').map((p) => p.split('=')));\n  if (!/^\\d+$/.test(partes.t || '') || !partes.v1) return false;\n\n  if (Math.abs(Date.now() / 1000 - Number(partes.t)) > tolerancia) return false;\n\n  const esperada = crypto\n    .createHmac('sha256', secreto)\n    .update(`${partes.t}.${cuerpoCrudo}`)\n    .digest('hex');\n\n  const a = Buffer.from(esperada);\n  const b = Buffer.from(partes.v1);\n\n  return a.length === b.length && crypto.timingSafeEqual(a, b);\n}\n```\n\nEn JavaScript, leé el cuerpo como texto o `Buffer` antes de convertirlo a objeto (por ejemplo con `express.raw({ type: 'application/json' })`).\n\n### Reintentos\n\nUna entrega es exitosa si tu servidor responde con un código `2xx` en 10 segundos o menos. Funnelchat no sigue redirecciones.\n\n- Se hacen hasta **4 intentos** por evento y suscripción. Entre un intento y el siguiente se espera 60, 300, 1800 segundos.\n- Se reintenta cuando hay un error de red o un timeout, ante un `5xx` y ante un `429`.\n- Un `3xx` o cualquier otro `4xx` es terminal: no se reintenta.\n- Después del último intento fallido la entrega queda como `failed`, sin más reintentos.\n\n### Estados de entrega\n\n`GET /api/v1/webhooks/{webhook}/deliveries` devuelve un registro por intento, con estos estados:\n\n| Estado | Significado |\n| --- | --- |\n| `pending` | El intento está en curso: todavía no hay resultado. |\n| `succeeded` | Tu servidor respondió `2xx`. |\n| `failed` con `next_attempt_at` | El intento falló y hay otro programado para esa fecha. |\n| `failed` sin `next_attempt_at` | El intento falló y no habrá más: era terminal o se agotaron los intentos. |\n\n### Probar una suscripción\n\n`POST /api/v1/webhooks/{webhook}/test` envía ahora un evento `webhook.test` firmado a la URL de la suscripción, sin esperar a que ocurra nada en tu cuenta, y responde con el resultado del intento. Funciona también sobre una suscripción inactiva, para probarla antes de activarla.\n\nLa respuesta es un ítem del historial de entregas, con la misma forma que cada elemento de `GET /api/v1/webhooks/{webhook}/deliveries`:\n\n```json\n{\n  \"data\": {\n    \"uuid\": \"0d3c2f4e-6a1b-4c8d-9e2f-5b7a1c3d4e6f\",\n    \"event_id\": \"evt_01hexample\",\n    \"event_type\": \"webhook.test\",\n    \"attempt\": 1,\n    \"status\": \"succeeded\",\n    \"http_status\": 200,\n    \"duration_ms\": 184,\n    \"error\": null,\n    \"next_attempt_at\": null,\n    \"created_at\": \"2026-01-15T12:00:00+00:00\",\n    \"updated_at\": \"2026-01-15T12:00:00+00:00\"\n}\n}\n```\n\n`status` es `succeeded` solo si tu servidor respondió `2xx`; si no, es `failed` y `error` indica la causa. La prueba aparece en el historial con `event_type: \"webhook.test\"`, no se reintenta y no consume tu cupo de eventos.\n\n### Suscripciones creadas con una clave de API\n\nUna suscripción creada, o reactivada, con una clave de API queda atada a esa clave. También la atan a una clave cambiar su URL con esa clave, o rotar su secreto con esa clave (rotarlo desde la sesión web no modifica el vínculo): la suscripción queda atada a la última credencial que fijó su destino. Si la clave se revoca (o vence, que cuenta como revocada), la suscripción deja de recibir eventos: pasa a `active: false` con `inactive_reason: \"key_revoked\"`, y no se le envían más eventos.\n\nEse cambio se ve a partir del primer evento que ocurra después de revocar la clave. Hasta entonces, un `GET` puede seguir mostrándola activa, pero no recibe eventos.\n\nLa prueba manual (`POST /api/v1/webhooks/{webhook}/test`) sigue funcionando sobre una suscripción inactiva.\n\nUna suscripción con `inactive_reason: \"key_revoked\"` no se puede reactivar: `PUT /api/v1/webhooks/{webhook}` con `\"active\": true` responde 422, sin importar la credencial que se use. Para seguir recibiendo eventos, creá una suscripción nueva con `POST /api/v1/webhooks`. Una suscripción que desactivaste a mano sí se puede reactivar con `PUT` y `\"active\": true`; queda atada a la credencial que la reactiva. Mientras esté activa, `inactive_reason` es `null`.\n\nLas suscripciones cuyo destino fijó por última vez la sesión web no dependen de ninguna clave: revocar una clave no las afecta.\n\n### Idempotencia\n\nUn mismo evento puede llegarte más de una vez (por ejemplo, si tu servidor procesó la entrega pero respondió tarde). Usá el campo `id` del sobre para descartar los que ya procesaste: es el mismo en todos los reintentos del evento.\n\n### Eventos disponibles\n\nSe generan desde el catálogo vigente. Los tipos marcados como **planificado** todavía no se emiten: se anuncian para que puedas prepararte, pero no los recibirás.\n\n`webhook.test` solo se envía con `POST /api/v1/webhooks/{webhook}/test`.\n\n#### `message.received`\n\nUn contacto le escribió a un número de WhatsApp de la cuenta.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000001\",\n    \"type\": \"message.received\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"message\": {\n            \"id\": 1001,\n            \"type\": \"text\",\n            \"text\": \"Hola, quiero más información\",\n            \"media\": null\n        },\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        },\n        \"receiver\": {\n            \"phone\": \"+5491100000001\"\n        },\n        \"device_id\": 4521\n    }\n}\n```\n\nValores posibles de `data.message.type`: `text`, `image`, `video`, `document`, `sticker`, `contact`, `audio`, `note`, `action`, `invalid`, `interactive`, `location`, `voice_call`, `video_call`, `event`, `button`, `template`, `notification`, `option_list`, `template_button_reply`, `poll`, `whatsapp_form`, `call_permission_request`, `call_permission_reply`, `request_contact_info`.\n\n`device_id` es el número de tu cuenta que recibió el mensaje: el mismo `device_id` que mandas para responder por ese número. Es `null` si el mensaje no tiene número asociado.\n\n#### `flow.completed`\n\nUn contacto terminó un flujo de automatización.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000003\",\n    \"type\": \"flow.completed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"flow\": {\n            \"id\": 3001,\n            \"name\": \"Flujo de ejemplo\"\n        },\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        }\n    }\n}\n```\n\nSe envía una sola vez por cada ejecución de un flujo, cuando termina con éxito. No se envía si la ejecución se cortó, se canceló, quedó bloqueada o falló. `contact` es `null` si la ejecución no tiene un contacto asociado. Un flujo muy usado puede generar muchos eventos seguidos.\n\n#### `broadcast.finished`\n\nUna campaña llegó a su estado final (enviada, fallida o con fallos parciales), con sus conteos.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000011\",\n    \"type\": \"broadcast.finished\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"broadcast\": {\n            \"id\": 6001,\n            \"name\": \"Campaña de ejemplo\"\n        },\n        \"status\": \"partially_failed\",\n        \"reason\": \"completed\",\n        \"totals\": {\n            \"processed\": 1200,\n            \"failed\": 30,\n            \"skipped_unreachable\": 12\n        }\n    }\n}\n```\n\n`status` es `success`, `failed` o `partially_failed`. `reason` dice por qué terminó: `completed` (se enviaron todas las páginas), `cancelled` (se cerró una campaña pausada), `template_rejected` (Meta rechazó la plantilla, o su categoría cambió, mientras la campaña esperaba), `approval_expired` (la plantilla no se aprobó a tiempo), `mac_lockout` (la cuenta alcanzó su límite de contactos activos), `no_recipients` (la audiencia quedó vacía) o `error` (el envío no pudo despacharse). `totals` son los conteos del envío: `processed` (destinatarios procesados), `failed` y `skipped_unreachable` (destinatarios que el canal no puede alcanzar); valen 0 si la campaña terminó antes de enviar. Se emite una sola vez por campaña.\n\n#### `contact.stage_changed`\n\nUn contacto cambió de etapa en un tablero.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000008\",\n    \"type\": \"contact.stage_changed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        },\n        \"board\": {\n            \"id\": 5001,\n            \"name\": \"Embudo de ejemplo\"\n        },\n        \"kind\": \"move\",\n        \"from_stage\": {\n            \"id\": 6001,\n            \"name\": \"Nuevo\",\n            \"position\": 0\n        },\n        \"to_stage\": {\n            \"id\": 6002,\n            \"name\": \"En seguimiento\",\n            \"position\": 1\n        }\n    }\n}\n```\n\nSe envía un evento por cada contacto que cambia de etapa en un tablero por etapas. `kind` es entry (entra al tablero, `from_stage` es null), move (pasa de una etapa a otra), exit (sale del tablero, `to_stage` es null) o stage_deleted (se reubica porque su etapa se borró; el nombre de la etapa borrada es null). No se envía si el contacto se coloca en la etapa en la que ya estaba.\n\n#### `message.status_changed`\n\nCambió el estado de entrega de un mensaje enviado.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000014\",\n    \"type\": \"message.status_changed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"message_id\": 1001,\n        \"contact_id\": 2001,\n        \"device_id\": 4521,\n        \"status\": \"failed\",\n        \"previous_status\": \"sent\",\n        \"error\": {\n            \"code\": 131047,\n            \"title\": \"Re-engagement message\",\n            \"reason\": null\n        },\n        \"occurred_at\": \"2026-10-01T12:00:00Z\",\n        \"client_reference\": \"pedido-1001\"\n    }\n}\n```\n\nSe emite cuando cambia el estado de entrega de un mensaje que enviaste a un contacto, ya sea desde el chat, una automatización o un asistente de IA (incluye los enviados con clave). No se emite para mensajes de difusiones ni para mensajes recibidos. `message_id` es el id que devuelve la API, `contact_id` el del contacto y `device_id` el número de tu cuenta por el que salió el mensaje, el mismo `device_id` que usas para enviar (`null` si no tiene). `status` es `sent`, `delivered`, `read` o `failed`. `previous_status` es el estado que el mensaje tenía justo antes de este cambio y es `null` en tres casos: es el primer aviso del mensaje, es el mismo estado que `status` (por ejemplo, el proveedor confirma el `sent` que ya registró el envío) o no se pudo leer. `error` solo viene cuando `status` es `failed`: `code` es el código numérico del proveedor y `title` su título, y cualquiera de los dos puede ser `null` si el proveedor no los informa. `error.reason` es `null` cuando el fallo lo informó el proveedor; cuando Funnelchat decidió que un mensaje enviado con clave no salía (por ejemplo, por saldo insuficiente o ventana de 24 horas cerrada) trae el motivo (`device_unavailable`, `insufficient_balance`, `window_closed`, `recipient_unreachable`, `template_not_found`, `template_unresolved_placeholder`, `not_queued` o `not_sent`), `code` es `null` y `title` es un texto llano en el idioma de la cuenta. `occurred_at` es el momento en que Funnelchat registró el estado, en UTC. `client_reference` es la referencia que mandaste al enviar el mensaje (por ejemplo `pedido-1001`) y `null` si el envío no la llevaba: sirve para relacionar cada aviso con tu envío también cuando la llamada de envío no respondió. Cada estado se informa una sola vez por mensaje: si llegan varios avisos juntos se informa el más avanzado y un aviso atrasado que no cambia el estado no genera evento. Un mensaje que no llegó a salir (por ejemplo, por ventana de 24 horas cerrada) no recibe avisos de estado, salvo uno enviado con clave: ese recibe un único aviso `failed` con `previous_status` en `null`, su `error.reason` y su `client_reference`. Un mensaje enviado con clave cuyo resultado no se conoce (el proveedor no respondió o el envío se interrumpió) no recibe aviso. Un mensaje cuyo envío no empezó dentro de la hora ya no sale: pasada la hora sin resultado, su estado es `null`, o `failed` con `error.reason` `not_sent` y su aviso si su envío llega tarde. Reintentar es un envío nuevo, que sólo puede duplicar si el envío había empezado y se cortó. Un mensaje `queued` no es enviado: su resultado llega por este evento o por la consulta del mensaje. En cuentas con mucho tráfico, los eventos que excedan el límite de entrega por minuto de la cuenta se descartan. Para recibirlo debes suscribirte a `message.status_changed` de forma explícita: una suscripción a `*` no lo incluye.\n\n#### `conversation.closed`\n\nUna conversación pasó a cerrada.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000004\",\n    \"type\": \"conversation.closed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        }\n    }\n}\n```\n\nSe envía cuando una conversación pasa de abierta a cerrada. No se envía si la conversación ya estaba cerrada ni cuando se reabre.\n\n#### `conversation.assigned`\n\nUna conversación quedó asignada a una persona del equipo o a un agente de IA.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000005\",\n    \"type\": \"conversation.assigned\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        },\n        \"assignee\": {\n            \"type\": \"human\",\n            \"name\": \"Agente de ejemplo\"\n        }\n    }\n}\n```\n\nSe envía cuando una conversación queda asignada a una persona del equipo (`assignee.type` = `human`) o a un agente de IA (`assignee.type` = `ai`), por cualquier camino. `assignee` trae el tipo y el nombre, nunca un identificador. No se envía al desasignar, ni cuando se vuelve a enviar el mismo asignado.\n\n#### `contact.tag_added`\n\nUn contacto recibió una etiqueta.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000006\",\n    \"type\": \"contact.tag_added\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        },\n        \"tag\": {\n            \"id\": 4001,\n            \"name\": \"Etiqueta de ejemplo\"\n        },\n        \"source\": \"manual\"\n    }\n}\n```\n\nSe envía un evento por cada contacto y etiqueta agregados, también en operaciones en bloque; no se envía si el contacto ya tenía la etiqueta. `source` indica el origen: manual, flow, bulk, import, sync, walink o ai. En operaciones en bloque grandes el límite de volumen de la cuenta puede descartar parte de los eventos.\n\n#### `broadcast.paused`\n\nUna campaña se pausó sola, por ejemplo porque bajó la calidad del número.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000007\",\n    \"type\": \"broadcast.paused\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"broadcast\": {\n            \"id\": 6001,\n            \"name\": \"Campaña de ejemplo\"\n        },\n        \"reason\": \"quality_degraded\",\n        \"quality\": \"YELLOW\",\n        \"quality_baseline\": \"GREEN\"\n    }\n}\n```\n\n`reason` es `quality_degraded` (la calidad del número bajó respecto de la del inicio, o llegó a RED) o `quality_unreadable` (no se pudo leer la calidad en tres controles seguidos). `quality` y `quality_baseline` son la calidad de Meta leída en el control y la del inicio del envío (`GREEN`, `YELLOW`, `RED`), o `null` si no se pudo leer. Sólo las campañas con envío inteligente se pausan solas. Reanudar la campaña y que se pause otra vez emite otro evento.\n\n#### `contact.tag_removed`\n\nUn contacto perdió una etiqueta.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000009\",\n    \"type\": \"contact.tag_removed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        },\n        \"tag\": {\n            \"id\": 4001,\n            \"name\": \"Etiqueta de ejemplo\"\n        },\n        \"source\": \"manual\"\n    }\n}\n```\n\nSe envía un evento por cada contacto y etiqueta quitados, también en operaciones en bloque; no se envía si el contacto no tenía la etiqueta. No se envía al borrar la etiqueta, al borrar o fusionar contactos ni al desvincular etiquetas de un tablero. `source` indica el origen: manual, flow, bulk o ai. En operaciones en bloque grandes el límite de volumen de la cuenta puede descartar parte de los eventos.\n\n#### `contact.created`\n\nSe creó un contacto nuevo en la cuenta.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000010\",\n    \"type\": \"contact.created\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\",\n            \"email\": \"contacto@example.com\"\n        }\n    }\n}\n```\n\nSe envía un evento por cada contacto nuevo, sea cual sea el canal: un mensaje entrante, la creación manual, una importación o la API. No se envía cuando el contacto ya existía y sólo se actualiza, ni para los contactos que la plataforma crea para sus propias notificaciones. En importaciones grandes el límite de volumen de la cuenta puede descartar parte de los eventos.\n\n#### `template.status_changed`\n\nUna plantilla cambió de estado de aprobación en Meta.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000012\",\n    \"type\": \"template.status_changed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"template\": {\n            \"id\": 7001,\n            \"uid\": \"1234567890\",\n            \"name\": \"plantilla_ejemplo\",\n            \"category\": \"MARKETING\"\n        },\n        \"previous_status\": \"PENDING\",\n        \"status\": \"APPROVED\",\n        \"reason\": null\n    }\n}\n```\n\n`template` identifica la plantilla igual que `GET /templates` (`id`, `uid`, `name`, `category`). `previous_status` y `status` son los estados tal como los devuelve la API (por ejemplo `PENDING`, `APPROVED`, `REJECTED`, `PAUSED`); `previous_status` es `null` si la plantilla no tenía estado. `reason` trae la observación de rechazo (traducida como en la API y limitada a 500 caracteres) cuando el cambio es un rechazo informado al crear la plantilla, y es `null` en el resto. No se emite si Meta reenvía el estado que la plantilla ya tenía. Si una misma plantilla de Meta figura en varias cuentas, cada cuenta recibe su propio evento.\n\n#### `flow.failed`\n\nLa ejecución de un flujo para un contacto terminó por un error.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000013\",\n    \"type\": \"flow.failed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"flow\": {\n            \"id\": 3001,\n            \"name\": \"Flujo de ejemplo\"\n        },\n        \"contact\": {\n            \"id\": 2001,\n            \"name\": \"Contacto de ejemplo\",\n            \"phone\": \"+5491100000000\"\n        },\n        \"reason\": \"execution_error\"\n    }\n}\n```\n\nSe envía una sola vez por cada ejecución de un flujo que termina por un error, no porque llegó al final. `reason` indica el motivo y toma uno de estos valores: `node_missing` (el paso a ejecutar ya no existe), `unknown_node_type` (el paso es de un tipo no reconocido), `missing_subflow` (el flujo que debía ejecutarse dentro de otro ya no existe), `malformed_node` (el paso tiene una configuración dañada), `loop_detected` (la ejecución dio vueltas sin esperar nada) y `execution_error` (un error inesperado detuvo la ejecución). No se envía si la ejecución se canceló, quedó bloqueada o se cortó porque se editó el flujo o se unieron contactos. `contact` es `null` si la ejecución no tiene un contacto asociado.\n\n#### `whatsapp_form.completed`\n\nUn contacto completó un formulario de WhatsApp.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000015\",\n    \"type\": \"whatsapp_form.completed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"form\": {\n            \"id\": 4001,\n            \"name\": \"Captar un lead\",\n            \"version_id\": 4002\n        },\n        \"message_id\": 1001,\n        \"contact_id\": 2001,\n        \"device_id\": 5001,\n        \"answers\": [\n            {\n                \"key\": \"nombre\",\n                \"label\": \"Nombre\",\n                \"value\": \"Contacto de ejemplo\"\n            },\n            {\n                \"key\": \"intereses\",\n                \"label\": \"Intereses\",\n                \"value\": [\n                    \"op_a\",\n                    \"op_b\"\n                ]\n            },\n            {\n                \"key\": \"comentarios\",\n                \"label\": \"Comentarios\",\n                \"value\": null\n            }\n        ],\n        \"occurred_at\": \"2026-10-01T12:00:00Z\"\n    }\n}\n```\n\nSe envía cuando un contacto completa un formulario, aunque la respuesta llegue tarde. Puede llegar más de una vez con el mismo `id`: deduplica por `id`. Si el contacto vuelve a enviar el mismo formulario, no se genera otro aviso: queda la primera respuesta. Cada respuesta de texto llega con a lo sumo 600 caracteres. `form.id` es el formulario (el mismo `family_id` de la lectura de formularios) y `form.version_id` la versión que recibió el contacto. `answers` es una lista con una entrada por pregunta, en el orden del formulario: `key` es el nombre de la pregunta, `label` su etiqueta y `value` la respuesta (texto, número, `true` o `false`, una lista de textos en opción múltiple, o `null` si no la contestó). En las preguntas de lista y de opción múltiple, `value` es el id de la opción. `message_id` es el id del mensaje del formulario y es `null` si el envío no tuvo un mensaje público; `device_id` es el número de WhatsApp por el que salió, o `null` si ya no es de la cuenta. `contact_id` es `null` si el contacto se eliminó antes de que saliera el aviso (las respuestas llegan igual); si se fusionó con otro, es el id del contacto que quedó. Mientras se fusionan dos contactos, el id puede ser el del contacto que se está fusionando.\n\n#### `webhook.test`\n\nEvento de prueba enviado desde la ruta de prueba de una suscripción.\n\n```json\n{\n    \"id\": \"evt_000000000000000000000002\",\n    \"type\": \"webhook.test\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"subscription\": \"00000000-0000-4000-8000-000000000001\",\n        \"sent_at\": \"2026-10-01T12:00:00Z\"\n    }\n}\n```\n\n### Otros webhooks de la plataforma\n\nLos webhooks de alertas y el nodo «Petición HTTP» de las automatizaciones son otros productos, con otro formato y otra configuración. No se administran con las rutas de esta sección ni llevan este sobre ni esta firma.\n\n## Listados\n\nCon una clave de API, los listados siempre responden una página con la forma `{ \"data\": [...], \"links\": {...}, \"meta\": {...} }`: `data` trae los ítems de la página, `links` las URL de `first`, `last`, `prev` y `next` (`null` cuando no hay página), y `meta` el detalle (`current_page`, `from`, `last_page`, `links`, `path`, `per_page`, `to`, `total`).\n\n- **Tamaño de página:** el parámetro `perPage` es un entero entre 1 y 100. Si no lo mandás, la página trae 25 ítems. Un valor mayor que 100, menor que 1 o que no sea un entero responde 422 con el detalle en `errors.perPage`. Algunos listados aceptan además `per_page` como alias con los mismos límites; si mandás `perPage` y `per_page` con valores distintos, la respuesta es 422 con el detalle en `errors.perPage`.\n- **Orden:** cada listado documenta los parámetros de orden que admite y los valores permitidos de cada uno (por ejemplo `orderBy` y `orderByMethod`). Un parámetro de orden que el listado no admite, o un valor fuera de la lista, responde 422 con el detalle en `errors.<parámetro>`.\n- **Páginas siguientes:** las URL de `links` y de `meta.links` conservan `perPage`, el orden y los filtros que admite el listado; los demás parámetros no se copian y sólo cambia `page`. En los listados que se piden por `POST`, los filtros viajan en el cuerpo y las URL llevan sólo `perPage` y `page`.\n- **Primero el permiso:** si tu clave no tiene el permiso del listado, la respuesta es la de siempre (401 o 403), aunque mandes un `perPage` inválido.\n\n## Envío de mensajes con clave\n\nCuando envías con una clave de API, antes de enviar se aplican reglas de protección de tu número y de tus contactos. Si una regla frena el envío, la respuesta es un JSON `{ \"error\": \"<código>\", \"message\": \"<explicación>\" }` y no se envía nada ni se registra ningún mensaje. Cada operación de envío documenta los códigos que puede responder.\n- **Ritmo:** el límite depende sólo del tipo de número por el que envías; en los envíos no hay un límite por minuto por clave ni por cuenta. Al superarlo, la respuesta es 429 con `error` = `rate_limited` y el encabezado `Retry-After`, que trae los segundos que debes esperar antes de reintentar. Las reacciones sólo tienen esta regla.\n  - **Número de WhatsApp Cloud (API oficial):** hasta 60 mensajes por segundo y hasta 10 mensajes por minuto al mismo contacto.\n  - **Número en coexistencia** (el mismo teléfono conectado a WhatsApp Cloud y a la aplicación WhatsApp Business del celular): hasta 15 mensajes por segundo en total entre las dos conexiones, envíes por la que envíes. El límite de 10 mensajes por minuto al mismo contacto aplica sólo a lo que envías por WhatsApp Cloud.\n  - **Número conectado por código QR** (sin coexistencia): esta regla no limita sus envíos.\n- **Ventana de 24 horas:** por un número de WhatsApp Cloud sólo puedes enviar mensajes que no son plantilla a un contacto que te escribió en las últimas 24 horas. Fuera de esa ventana la respuesta es 422 con `error` = `window_closed`; para retomar la conversación envía una plantilla aprobada, que no tiene esta restricción.\n- **Antibloqueo:** en las últimas 24 horas, un mismo contenido se puede enviar como máximo 2 veces al mismo contacto (el siguiente responde 422 con `error` = `antiblock_duplicate_content`), y como máximo 5 mensajes seguidos sin que el contacto responda (el siguiente responde 422 con `error` = `antiblock_unanswered_limit`). Cuando el contacto responde, los contadores se reinician. Aplica a mensajes y a plantillas, no a reacciones.\n- **Destinatario:** `recipient_mismatch` (422) indica que el teléfono o el identificador de WhatsApp que mandaste en el cuerpo no corresponde al contacto de la ruta (sólo las operaciones que reciben ese dato en el cuerpo). `recipient_unsupported` (422) indica que el contacto es un grupo, una lista de difusión o un canal: por la API sólo se escribe a personas individuales.\n- **Estados de entrega:** el evento de webhook `message.status_changed` (enviado, entregado, leído, fallido) no se incluye al suscribirte a `*`: tienes que pedirlo de forma explícita en `events` al crear o editar la suscripción.\n- **Resultado de tus envíos:** cuando envías con una clave, la llamada no espera al proveedor: la respuesta trae el mensaje ya registrado y en cola, el mismo objeto que devuelve `GET /contacts/{contact}/messages/{message}`, y el envío sale enseguida después.\n  - **En cola no es enviado:** `status` `queued` solo dice que registramos el mensaje y que está por salir. El resultado llega por el evento `message.status_changed` o consultando `GET /contacts/{contact}/messages/{message}`. Un mensaje `queued` no se reintenta: reenviarlo lo duplicaría.\n  - **Aceptado no es entregado:** `status` `sent` solo dice que el proveedor aceptó el mensaje. El estado final (entregado, leído o fallido) llega por el evento `message.status_changed` o consultando `GET /contacts/{contact}/messages/{message}`.\n  - **`failed`:** el proveedor rechazó el mensaje dando un motivo, o Funnelchat lo frenó antes de enviarlo. No salió: reintentar es un intento nuevo y no lo duplica. Cuando lo decidió Funnelchat, `error.reason` trae el motivo, `error.code` es `null` y `error.title` es un texto llano en tu idioma; si lo rechazó el proveedor, `error.reason` es `null`. Qué hacer según `error.reason`: `device_unavailable`, reconecta el número en Funnelchat y envía de nuevo; `insufficient_balance`, recarga tu billetera de WhatsApp; `window_closed`, envía una plantilla aprobada; `recipient_unreachable`, revisa el teléfono del contacto; `template_not_found` o `template_unresolved_placeholder`, corrige la plantilla o sus variables; `not_queued` o `not_sent`, vuelve a intentarlo. Un mensaje enviado con clave que termina `failed` también llega por `message.status_changed`, con `previous_status` en `null` y su `client_reference`; un `status` `null` no recibe aviso.\n  - **`status` `null`:** el proveedor no confirmó ni rechazó el envío (no respondió, respondió con una falla sin motivo o el envío se interrumpió). Puede haber llegado al contacto, no recibirá avisos de estado y reintentarlo puede duplicarlo.\n  - **Más de una hora en `queued`:** un mensaje cuyo envío no empezó dentro de la hora ya no sale. Pasada la hora sin resultado, su `status` es `null`, o `failed` con `error.reason` `not_sent` y su aviso `message.status_changed` si su envío llega tarde. Reintentar es un envío nuevo, que sólo puede duplicar si el envío había empezado y se cortó.\n  - **Error 5xx o llamada sin respuesta:** busca tu `client_reference` en el historial del contacto antes de reintentar, y hazlo al menos un minuto después de la llamada. Si aparece, el mensaje quedó registrado: no lo reenvíes, su resultado llega por `message.status_changed` o consultando `GET /contacts/{contact}/messages/{message}`; la excepción son las tarjetas y los destinos de un reenvío tras un 5xx: si todos los que aparecen vienen `failed` con `not_queued`, se reintenta la llamada completa; si alguno aparece `queued`, quedó registrado: no lo reenvíes. Si no aparece, no salió nada y puedes reintentar. Repetir una referencia no evita duplicados: dos llamadas con la misma `client_reference` registran dos mensajes.\n  - **Error 404 en un envío:** el contacto no existe. En un reenvío, también cuando el mensaje de origen no existe o no es de ese contacto.\n  - **`POST /contacts/{contact}/message`:** la respuesta trae el mensaje en `message`: `queued` si es un mensaje, o el mensaje registrado de una nota.\n  - **`POST /contacts/{contact}/message/contact-card`:** la respuesta trae `messages`: un mensaje por tarjeta, en el orden de `contact_card_ids`, cada uno con su `id` y en cola (`queued`). Todas salen después, desde la cola: el resultado de cada una llega por `message.status_changed` o consultando `GET /contacts/{contact}/messages/{message}`, con tu `client_reference`. Si una tarjeta no pudo encolarse, su entrada viene `failed` con `error.reason` `not_queued`: no salió y volver a enviar esa tarjeta es un intento nuevo. Si alguna no pudo registrarse, la llamada responde un error 5xx y ninguna tarjeta salió: las que ya aparezcan en el historial del contacto vienen `failed` con `error.reason` `not_queued` y su propio aviso `message.status_changed` `failed`. Si todas las que aparecen vienen `failed` con `not_queued`, reintenta la llamada completa; si alguna aparece `queued`, quedó registrada: no la reenvíes.\n  - **Reenvío:** la respuesta trae un elemento por destino, en el orden de `targets`, y cada destino que quedó en cola trae su `message` con su `id` y en cola (`queued`). Todos salen después, desde la cola: el resultado de cada uno llega por `message.status_changed` o consultando `GET /contacts/{contact}/messages/{message}`, con tu `client_reference`. Un destino que no pudo encolarse viene `blocked` con `reason` `not_sent` y su `message` `failed` con `error.reason` `not_queued`: no salió y volver a reenviarlo a ese destino es un intento nuevo. Un destino `blocked` por MAC (`mac_limit_reached` o `mac_lockout_24h`) o con `reason` `target_not_found` (no existe o no es de tu cuenta) o `device_unavailable` trae `message` `null`: no salió nada. Si algún destino no pudo registrarse, la llamada responde un error 5xx y ninguno salió: los que ya aparezcan en el historial del contacto vienen `failed` con `error.reason` `not_queued` y su propio aviso `message.status_changed` `failed`. Si todos los que aparecen vienen `failed` con `not_queued`, reintenta la llamada completa; si alguno aparece `queued`, quedó registrado: no lo reenvíes.\n  - **`POST /contacts/{contact}/message/form`:** la respuesta trae solo `message`: el mensaje del formulario en cola (`queued`). Si no pudo ponerse en cola, la respuesta sigue siendo 200 con el mensaje en estado `failed` y `error.reason` `not_queued`: no salió, así que reintentar no lo duplica. Su resultado llega por `message.status_changed` o consultando `GET /contacts/{contact}/messages/{message}`, y la respuesta del contacto por `whatsapp_form.completed`. Si tu cuenta está en bloqueo por el límite de contactos activos responde 429 `mac_lockout_24h` y no guarda ningún mensaje ni `client_reference`. Sus errores propios están en la guía «Formularios de WhatsApp».\n  - **`POST /message/send-message` y `POST /devices/{device}/templates/{template_id}/send-template`:** la respuesta trae solo `message`: el mensaje en cola (`queued`), o el mensaje registrado de una nota en `send-message`. Si una variable de la plantilla se completa con un campo personalizado que no existe en tu cuenta, `send-template` responde 422 con `error` `template_unresolved_placeholder`, `placeholders` (hasta 20) y `count` (el total), y no registra ni envía nada; si la plantilla no existe en tu cuenta, responde 404 `template_not_found`.\n- **Correlacionar tus envíos:** manda `client_reference` en el cuerpo (texto opcional de 1 a 64 caracteres visibles, sin espacios) para identificar cada envío con tu propia referencia. La misma referencia vuelve en el historial de mensajes del contacto y en el evento `message.status_changed`, de modo que puedes relacionar cada aviso de estado con tu envío también cuando la llamada de envío no respondió. La referencia no es única (dos envíos pueden usar el mismo valor) y no está autenticada: la ven todas las claves y todas las suscripciones de la cuenta. Por eso relaciónala siempre junto con `message_id` y `contact_id`, y trátala como texto no confiable cuando la muestres. No pongas datos personales en la referencia. Una llamada que frena una regla de protección de esta sección (ritmo, ventana de 24 horas, antibloqueo o destinatario) no registra ningún mensaje ni referencia. Un rechazo por MAC (`mac_limit_reached` o `mac_lockout_24h`) es distinto: guarda un mensaje con estado de error que lleva la referencia; el envío de formularios (`POST /contacts/{contact}/message/form`) es la excepción: con `mac_lockout_24h` responde 429 y no guarda ningún mensaje ni referencia. Un mensaje enviado con clave que Funnelchat frena antes de que salga (por ejemplo, por saldo insuficiente) aparece en el historial con estado de error y su referencia, y recibe un aviso `failed` con esa referencia; uno enviado desde el panel no recibe avisos de estado. Las reacciones no aceptan `client_reference`.\n\n## Enviar un archivo por URL\nNo subes el archivo a Funnelchat: en `file` mandas la dirección (URL) del archivo y WhatsApp o el proveedor lo descarga desde ahí. Funnelchat no abre la URL al recibir tu llamada, así que un archivo inaccesible, vencido o fuera de los límites se conoce al enviarlo: el mensaje termina `failed` con el error del proveedor.\n- **La URL:** `file` admite hasta 4096 caracteres; más de eso se rechaza con un 422 en `file`. Si `file` empieza con `http`, en mayúsculas o minúsculas, tiene que ser una URL que empiece con `http://` o `https://`; si no (por ejemplo `httpfoto.jpg`), la respuesta es 422 con el error en `file`. Te recomendamos `https://`; `http://` también se acepta, pero viaja sin cifrar. Debe poder descargarse sin credenciales; puede ser una URL firmada. Tiene que seguir válida hasta que el mensaje sale: un envío con clave puede esperar en cola hasta 54 minutos, así que usa URLs que duren al menos una hora. No pongas secretos en la ruta ni en el dominio de la URL: en los registros de actividad (logs) del envío que escribe Funnelchat, de la URL quedan sólo el esquema, el dominio y la ruta (sin el usuario y la contraseña, la parte de consulta después de `?` ni el fragmento después de `#`) y del resultado sólo identificadores, el tipo del mensaje y, del error del proveedor, sus códigos y, sólo si tu número es de WhatsApp Cloud, su categoría, su título corto y su identificador de traza, nunca el texto de la respuesta del proveedor; la ruta y el dominio sí quedan. La URL completa viaja a WhatsApp o al proveedor de tu número, que la descarga y puede guardarla en sus propios registros. Además, la URL completa, con su consulta, se guarda en el historial del contacto, la ven los usuarios de tu cuenta y se copia al reenviar el mensaje: usa URLs firmadas de corta duración (al menos el tiempo de la cola, cerca de una hora) y limitadas a un solo archivo.\n- **El tipo:** decide la extensión de la ruta de la URL si es una de la lista; si no, el final de la URL completa si es una de la lista. Si la ruta no termina en una extensión de la lista y sólo lo hace el final de la URL completa (por ejemplo `https://cdn.example.com/video.mov?poster=frame.jpg`), el mensaje queda registrado con ese tipo, pero WhatsApp o el proveedor pueden enviarlo según la extensión de la ruta; si necesitas un tipo fijo, envía `file_type`:\n  - `.jpg`, `.jpeg`, `.png`: `image`\n  - `.webp`: `sticker`\n  - `.ogg`, `.oga`, `.mp3`, `.m4a`, `.aac`, `.opus`, `.wav`: `audio`\n  - `.gif`, `.mp4`: `video`\n  - `.doc`, `.docx`, `.pdf`: `document`\n- **Cuándo envías `file_type`:** si la URL no termina en una extensión reconocida (por ejemplo una URL firmada sin extensión), la respuesta es 422 con el error en `file_type`: agrega `file_type` con uno de estos valores: `image`, `video`, `audio`, `document`, `sticker`. Cuando lo envías, manda sobre la extensión: sirve también para un archivo cuya extensión no es de los tipos de la lista, como `.xlsx`, que se envía con `file_type` = `document` y `file_name` (por ejemplo `reporte.xlsx`), porque un documento cuya URL no termina en una extensión de la lista necesita su nombre. Si la URL termina en una extensión que no es la del archivo (como `/descarga.php?id=7`) y no envías `file_type`, la respuesta es 415 con la extensión recibida (`php`); con `file_type` se envía y, si es un documento, también hace falta `file_name`.\n- **Extensión no soportada:** si la ruta de la URL termina en un formato real que no enviamos solos (por ejemplo `.xlsx` o `.zip`), la URL completa no termina en una extensión de la lista y no mandas `file_type`, la respuesta es 415 con la extensión recibida.\n- **El nombre del archivo:** `file_name` (opcional, hasta 255 caracteres, sin `/`, `\\`, `?`, `#` ni caracteres de control) es el nombre con el que el contacto ve un documento; llévalo siempre con su extensión, por ejemplo `factura.pdf`. Es obligatorio cuando envías un documento por URL y la URL no termina en una extensión de la lista: sin él la respuesta es 422 con el error en `file_name`.\n- **Formatos y tamaños:** los formatos aceptados por WhatsApp y el tamaño máximo de cada tipo son:\n  - `image`: image/jpeg, image/png, image/webp; hasta 5 MB.\n  - `video`: video/mp4, video/3gpp, image/gif; hasta 16 MB.\n  - `audio`: audio/aac, audio/mp4, audio/mpeg, audio/amr, audio/ogg, audio/opus; hasta 16 MB.\n  - `document`: text/plain, application/pdf, application/vnd.ms-powerpoint, application/msword, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; hasta 100 MB.\n  - `sticker`: image/webp; hasta 100 KB si es estático y 500 KB si es animado.\n- **Historial y reenvío:** el historial del contacto guarda la URL tal cual la enviaste, y el nombre `file_name` no se guarda. Al reenviar un mensaje cuyo archivo es una URL, se reenvía la misma URL; con una extensión de la lista, como esa extensión indica; si no, un mensaje que enviaste se reenvía con su tipo sólo cuando su extensión es un formato que WhatsApp acepta para ese tipo (los de «Formatos y tamaños», por ejemplo `.3gp` para `video` o `.amr` para `audio`). Una URL sin extensión, un formato no aceptado, un documento cuya URL no termina en una extensión de la lista (por ejemplo `/descarga.php?id=7`) o un mensaje recibido sin una extensión de la lista no se puede reenviar: la respuesta es 422 con `error` = `not_forwardable` y `reason` = `unsupported_file_extension`.\n\n## Formularios de WhatsApp\n\nUn formulario de WhatsApp es un conjunto de pantallas con preguntas que tu contacto abre y completa dentro del chat. Con la API puedes armarlo, publicarlo, enviarlo a un contacto y recibir sus respuestas. Sólo funciona con números de WhatsApp Cloud (API oficial) de tu cuenta, y sólo se puede enviar dentro de las 24 horas siguientes al último mensaje del contacto a ese número. Los números conectados por código QR no sirven para formularios.\n- **Identificadores:** un formulario tiene un identificador estable y una versión por cada vez que lo cambias. No los confundas:\n\n  | Qué es | Dónde aparece |\n  |---|---|\n  | **Formulario** (estable, el mismo en todas sus versiones) | `family_id` en las respuestas de formularios, `{familyId}` en las rutas `/forms/families/{familyId}/…`, `form_id` al enviar y `data.form.id` en `whatsapp_form.completed` |\n  | **Versión** (cambia con cada versión nueva) | `id` en las respuestas de formularios, `{id}` en las rutas `/forms/{id}/…` de edición, publicación y números, y `data.form.version_id` en `whatsapp_form.completed` |\n\n  Al enviar pides el formulario, no la versión: sale la versión publicada vigente. Si publicas una versión nueva, lo que se envía cambia sin que cambies tu integración.\n- **Recorrido, paso a paso:**\n  1. **Crea el formulario:** `POST /forms` con `template_key` `blank` (un formulario para armar desde cero; `GET /forms/templates` lista las demás plantillas), `device_id` (el número de WhatsApp Cloud de tu cuenta) y, si quieres, `device_ids` con otros números. Responde `201` con la versión en borrador (`id`), su `family_id`, `lint` y `numbers`. Un formulario no se crea mandando su contenido: el contenido va en el paso siguiente. Ojo con `blank`: no viene vacío, trae una pantalla (`SCREEN_BLNK`) sin elementos cuyo `next` es `complete`, es decir, que termina el formulario. Si en el `PUT` conservas esa pantalla y agregas otra, la segunda queda inalcanzable y `lint` marca `screen_unreachable` (error que impide publicar) hasta que el `next` de la primera apunte a la segunda (o `auto`, que sigue el orden). Lo más simple es reemplazar `screens` entera con tus propias pantallas.\n  2. **Arma la definición:** `PUT /forms/{id}` con `definition` (`screens`, cada una con `id`, `title`, `cta`, `next` e `items`) y, si quieres, `name` y `expected_updated_at`. El servidor guarda la definición tal como llega y la respuesta trae `lint` junto a `data`: una lista de `{code, severity, screenId, itemId, message}` con lo que falta corregir. Lo incompleto se guarda igual; los errores (`severity` `error`) impiden publicar y los avisos (`aviso`) no. Una definición con la forma rota responde `422`. Para leerla de nuevo, `GET /forms/{id}` trae la versión con su definición y `GET /forms/families/{familyId}/definition` la del formulario: la de la versión publicada vigente o, si todavía no hay ninguna, la de la más nueva. Con `expected_updated_at` evitas pisar un cambio más nuevo: si no es el último guardado responde `409` `STALE`.\n  3. **Valida en Meta (opcional):** `POST /forms/{id}/sync` corre el linter, sube el formulario a Meta y trae sus observaciones en `lint` con `code` `meta`, sin publicar. Si la definición tiene errores responde `422` `LINT`, igual que al publicar.\n  4. **Publica:** `POST /forms/{id}/publish` hace la validación y publica; es inmediato. Si la definición tiene errores responde `422` `LINT` con la lista, y si Meta la rechaza, `502` `META`. Un formulario sin ninguna pregunta no se puede publicar. Los otros números del formulario se publican en segundo plano: consulta su estado (`draft`, `publishing`, `published` o `failed`) en `GET /forms/{id}/numbers`.\n  5. **Suma o quita números (opcional):** `POST /forms/{id}/numbers` con `device_id` publica el formulario en otro número de WhatsApp Cloud de tu cuenta, `POST /forms/{id}/numbers/retry` reintenta los que fallaron y `DELETE /forms/{id}/numbers/{deviceId}` quita uno. El número con el que creaste el formulario no se quita: `422` `PRIMARY_NUMBER`. Un número que no es de tu cuenta o no es WhatsApp Cloud responde `422` `NUMBER_NOT_ELIGIBLE`.\n  6. **Envía:** `POST /contacts/{contact}/message/form` con `form_id` (el formulario, no la versión) y `device_id`; opcionalmente `text` (hasta 1024 caracteres), `button_text` (hasta 30, sin emojis) y `client_reference`. Sólo se envía con una clave de API. La clave de un asiento sólo envía a los contactos asignados a ese asiento (con cualquier otro contacto responde el `404` de un contacto que no existe); la clave del titular envía a cualquier contacto de la cuenta. Responde `200` con `message` en cola (`queued`); sus errores propios están al final de esta guía.\n  7. **Recibe las respuestas:** suscríbete al evento `whatsapp_form.completed` (también llega si te suscribes a `*`) o lee `GET /forms/families/{familyId}/responses` y `GET /forms/families/{familyId}/responses/{runId}`. `GET /forms/families/{familyId}/metrics` trae los envíos, aperturas y respuestas.\n  - **Cambiar un formulario publicado:** un formulario publicado no se edita (`PUT` y `DELETE` responden `409` `PUBLISHED`). Crea una versión nueva con `POST /forms/{id}/versions`, que nace como borrador (`201`, o `200` con `created: false` si ya había un borrador), edítala y publícala. El `form_id` no cambia: el envío usa la versión publicada vigente.\n- **Reglas de la definición:** el servidor no genera ni corrige identificadores: quien arma la definición los genera, y deben ser válidos y únicos. Meta acepta sólo letras y guiones bajos.\n  - **Pantallas:** `id` con `SCREEN_` más letras (por ejemplo `SCREEN_ABCD`), sin dígitos, y únicos en el formulario. `next` es `auto` (la siguiente), `complete` (termina) o el `id` de una pantalla posterior: sólo se salta hacia adelante.\n  - **Preguntas:** `name` en minúsculas y guiones bajos (`a-z` y `_`), único en todo el formulario. Sin dígitos, tildes, `ñ` ni espacios. No uses los nombres reservados `flow_token`, `version` ni `extension_message_response`. No cambies un `name` después de crearlo: las respuestas, las ramas y las etiquetas lo usan.\n  - **Opciones:** `id` de cada opción en minúsculas y guiones bajos, único en su pregunta (por ejemplo `op_comercio`).\n  - **Qué marca el linter:** `field_name_reserved` (nombre reservado), `field_name_invalid` (nombre fuera de letras y guiones bajos) y `option_id_invalid` (id de opción fuera de ese alfabeto) son errores que impiden validar y publicar. El linter no revisa que los identificadores sean únicos ni que existan los campos personalizados y las etiquetas que referencias: compruébalo tú.\n  - **Campos personalizados y etiquetas:** si una pregunta guarda su respuesta en un campo personalizado (`map` con `target` `custom` y `key` con el nombre del campo) o asigna etiquetas (`tagMap`, con el nombre de la etiqueta), ese campo y esa etiqueta tienen que existir en tu cuenta. El formulario no los crea: si no existen, la respuesta se guarda en el formulario pero no se escribe en el contacto ni se le asigna la etiqueta. Un campo numérico sólo admite preguntas `number` y uno de fecha sólo preguntas `date`; el servidor no lo revisa.\n  - **No se pueden publicar** los formularios que necesitan un servidor propio (`endpoint` en `true`, opciones en vivo): el linter los marca como error.\n- **Límites del formulario:** hasta 5 pantallas, 50 elementos por pantalla, 3 imágenes por pantalla y 2 enlaces por pantalla; pasarse es un error que impide publicar. El nombre del formulario admite hasta 120 caracteres. Las imágenes (`type` `image`, con `src` en base64 sin el prefijo `data:`) deben ser JPG o PNG, de hasta 300 KB cada una y 4 MB entre todas las del formulario; el servidor no revisa su tamaño ni su formato, así que quien arma la definición debe respetarlos. El guardado acepta un `src` con el prefijo `data:`, pero se envía a Meta tal como lo guardaste y Meta dibuja un recuadro roto: manda siempre la carga en base64 pelada, sin prefijo.\n  - **Tope de cada guardado:** además, un guardado rechaza (`422`) una definición con más de 20 pantallas, 100 elementos en una pantalla o 200 opciones en una pregunta. Esos topes quedan por encima de los límites de arriba. Además, cada guardado envía la definición entera, imágenes incluidas, y debe pesar menos de unos 6 MB: pasado ese tamaño la plataforma rechaza la llamada antes de que llegue al formulario, así que no cuentes con más.\n- **Qué puede hacer cada clave:** los permisos se heredan hacia abajo: `conversations:send` incluye `conversations:write`, que incluye `conversations:read`. Con `read` lees formularios, su definición (`GET /forms/families/{familyId}/definition`), versiones, números, respuestas y métricas; con `write` además armas, guardas, publicas, validas, creas versiones, eliminas borradores y sumas, reintentas o quitas números; con `send` además envías. Por eso una clave con `conversations:send`, aunque sólo la hayas pensado para enviar, también puede armar, publicar y quitar números de formularios: dale `send` sólo a quien confías para eso. Las operaciones `summary`, `analysis` y `deliveries` del panel no están abiertas a claves.\n  - **Topes de llamadas por clave:** cada clave puede hacer hasta 120 lecturas por minuto y hasta 60 escrituras por minuto en formularios (cada clave lleva su propio contador: dos claves de la misma cuenta, sea del titular o de un asiento, no se frenan entre sí, y ninguna gasta el tope del panel). Al superarlos la respuesta es `429` con el encabezado `Retry-After`, que trae los segundos que debes esperar. Validar, publicar y tocar números tienen además el tope de 30 por minuto compartido por toda la cuenta, que se explica en los errores al final de esta guía.\n  - **Cuenta:** la clave de un asiento (un agente) opera sobre los formularios del titular de la cuenta, no sobre formularios propios del asiento.\n  - **Respuestas con clave de un asiento:** `responses` y `responses/{runId}` se limitan a los contactos que ese asiento puede ver en Funnelchat; las métricas (`metrics`) cuentan todas las respuestas del formulario.\n  - **Detalle de una respuesta con clave:** `GET /forms/families/{familyId}/responses/{runId}` no trae `last_error` en sus efectos; el resto de cada efecto es igual al del panel.\n- **Aviso `whatsapp_form.completed`:** `data.form` trae `id` (el formulario), `name` y `version_id` (la versión que recibió el contacto); `message_id` es el mensaje del formulario y puede ser `null`; `answers` es una lista de `{key, label, value}`, una por pregunta y en el orden del formulario (`key` es el `name` de la pregunta, y `value` es `null` si no la contestó). El mismo aviso puede llegar más de una vez con el mismo `id`: deduplica por `id`. Cada respuesta de texto llega con a lo sumo 600 caracteres. Si el contacto vuelve a enviar el mismo formulario no se genera otro aviso: queda la primera respuesta. Los detalles y el ejemplo están en la sección «Webhooks».\n- **Errores al armar y publicar:** `404` si el `id` no existe o no es de tu cuenta (un id de otra cuenta responde igual); `409` `STALE` (el guardado no es el último) y `409` `PUBLISHED` (la versión ya está publicada); `422` `LINT` al publicar con errores en la definición, `422` `NUMBER_NOT_ELIGIBLE` y `422` `PRIMARY_NUMBER` en los números; `502` `META` si Meta rechaza la operación o no responde. Validar, publicar y tocar números (`sync`, `publish` y las operaciones de `numbers`) sube a Meta, que limita por cuenta de WhatsApp Business: todas las claves de tu cuenta, la del titular y las de los asientos, comparten un tope de 30 de estas llamadas por minuto. Al superarlo responde `429` con el encabezado `Retry-After`, que trae los segundos que debes esperar.\n- **Errores al enviar un formulario:** además de los errores de las reglas de protección de esta documentación, `POST /contacts/{contact}/message/form` responde: `404` si el contacto no existe, no es de tu cuenta o, con la clave de un asiento, no está asignado a ese asiento; `404` con `form_not_found` si el formulario no existe en tu cuenta; `422` con `device_unavailable` (el número no es de tu cuenta o no está conectado), `number_not_eligible` (no es un número de WhatsApp Cloud que pueda enviar formularios), `form_not_published` (el formulario no tiene versión publicada: publícalo), `form_not_on_number` (no está publicado en ese número: súmalo con `POST /forms/{id}/numbers` y espera a que se publique), `recipient_unreachable` (el contacto no tiene teléfono ni identificador de WhatsApp al que ese número pueda escribir) y `window_closed` (pasaron más de 24 horas desde el último mensaje del contacto); `429` con `rate_limited` y `Retry-After` si superas el ritmo; y `422` con `not_sent` (el destinatario que se registró no coincide con el contacto verificado, o el mensaje no quedó como un envío de la conversación: no se registró ni salió nada y puedes reintentar; son las únicas dos situaciones y en el uso normal no ocurren). Si Funnelchat no pudo poner el mensaje en cola, la respuesta no es un error: es `200` con el mensaje en estado `failed` y `error.reason` `not_queued`; no salió, así que reintentar no lo duplica. Si tu cuenta está bloqueada por el límite de contactos activos, el envío responde `429` con `mac_lockout_24h`, como los demás envíos con clave, pero a diferencia de ellos no guarda ningún mensaje ni `client_reference`: no queda nada en el historial del contacto ni se puede buscar por la referencia, así que reintenta cuando termine el bloqueo. Un `500` indica que el mensaje no pudo registrarse. Si la llamada no responde o da un error 5xx, busca tu `client_reference` en el historial del contacto antes de reintentar.\n\n## Contactos inactivos por MAC\n\nTu plan incluye un límite de contactos activos (MAC) por ciclo. Cuando lo alcanzas, empiezan 24 horas de gracia en las que todo sigue funcionando. Si terminan sin que sumes capacidad, tu cuenta entra en bloqueo: `GET /mac/status` responde `state` = `enforcing`.\n- **Contacto inactivo:** mientras tu cuenta está en bloqueo, es inactivo todo contacto que todavía no es un contacto activo del ciclo actual. A los contactos que ya son activos en el ciclo puedes seguir escribiéndoles con normalidad.\n- **Cuándo deja de serlo:** cuando tu cuenta sale del bloqueo, al sumar capacidad (por ejemplo, con una compra o un cambio de plan) o al empezar un ciclo nuevo con cupo disponible. No hace falta ninguna acción sobre el contacto.\n- **`GET /mac/status`:** `state` puede ser `normal`, `grace` (corren las 24 horas de gracia), `enforcing` (bloqueo) o `cleared` (el último período de gracia o de bloqueo ya terminó). `inactive_contacts_count` (entero) cuenta los contactos que quedaron registrados como inactivos en el ciclo actual: aquellos a los que se les frenó un mensaje, que te escribieron estando inactivos o que una difusión dejó afuera. No es el total de contactos que podrían ser inactivos: para saber si lo es un contacto puntual, usa `is_mac_inactive`. Si tu cuenta no tiene activo el control de contactos activos, la respuesta trae `enforcement_enabled` en `false` y no incluye este campo.\n- **`is_mac_inactive`** (booleano): viene en cada contacto de `GET /contacts` y de `GET /contacts/{contact}`, y en cada conversación de `GET /conversations`. Es `true` si el contacto es inactivo en el momento de la consulta.\n- **Envíos a un contacto inactivo:** `POST /contacts/{contact}/message`, `POST /message/send-message` y `POST /contacts/{contact}/message/contact-card` responden `429` con `error` = `mac_lockout_24h`, igual que desde el panel, y guardan en el historial del contacto un mensaje con estado de error que lleva tu `client_reference`. Esta respuesta no trae `Retry-After`: el envío vuelve a funcionar cuando el contacto deja de ser inactivo. `POST /contacts/{contact}/message/form` responde el mismo `429` pero no guarda ningún mensaje. En un reenvío (`POST /contacts/{contact}/messages/{message}/forward`) la respuesta es por destino: cada destino inactivo viene con `status` `blocked`, `reason` `mac_lockout_24h` y `message` `null`, y los demás destinos siguen su curso.\n- **`POST /kanban-settings/{kanbanSetting}/bulk-move`:** mueve sólo los contactos que no son inactivos; los inactivos se quedan donde estaban, sin error. Si dejó afuera a alguno, la respuesta es `200` con `{ \"excluded_inactive\": <cantidad> }`; si no, el cuerpo es `null`."}, "servers": [{"url": "https://api.funnelchat.com/api/v1"}], "security": [{"http": []}], "paths": {"/broadcasts": {"get": {"operationId": "broadcast.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts", "tags": ["Broadcast"], "parameters": [{"name": "name", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "device_id", "in": "query", "schema": {"type": ["integer", "null"]}}, {"name": "status[]", "in": "query", "schema": {"type": "array", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], "items": {"type": "string", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]}}}, {"name": "folder_id", "in": "query", "schema": {"type": ["integer", "null"]}}, {"name": "unclassified", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "send_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["immediate", "scheduled", null]}}, {"name": "device_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["business", "api", null]}}, {"name": "send_at_from", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "send_at_to", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/BroadcastsResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/broadcasts/contacts": {"post": {"operationId": "broadcast.contacts", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /broadcasts/contacts", "tags": ["Broadcast"], "parameters": [{"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"tags": {"type": "array", "items": {"type": "string"}}, "some_tags": {"type": "array", "items": {"type": "string"}}, "exclude_tags": {"type": "array", "items": {"type": "string"}}, "countries": {"type": "array", "items": {"type": "string"}}, "date_from": {"type": ["string", "null"], "format": "date-time"}, "date_to": {"type": ["string", "null"], "format": "date-time"}, "only_with_phone": {"type": "boolean"}, "only_paused": {"type": "boolean"}, "kanban_setting_id": {"type": ["integer", "null"]}, "kanban_stage_ids": {"type": ["array", "null"], "items": {"type": "integer"}}, "only_stagnant": {"type": ["boolean", "null"]}, "exclude_never_replied": {"type": "boolean"}, "lead_score_categories": {"type": ["array", "null"], "items": {"type": "string", "enum": ["insufficient_data", "hot", "warm", "cold"]}}, "lead_score_min": {"type": ["integer", "null"], "minimum": 0, "maximum": 100}, "lead_score_max": {"type": ["integer", "null"], "minimum": 0, "maximum": 100}, "per_page": {"type": ["integer", "null"], "minimum": 1}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/BroadcastContactResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/broadcasts/contacts-count": {"post": {"operationId": "broadcast.contactsCount", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /broadcasts/contacts-count", "tags": ["Broadcast"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"tags": {"type": "array", "items": {"type": "string"}}, "some_tags": {"type": "array", "items": {"type": "string"}}, "exclude_tags": {"type": "array", "items": {"type": "string"}}, "countries": {"type": "array", "items": {"type": "string"}}, "date_from": {"type": ["string", "null"], "format": "date-time"}, "date_to": {"type": ["string", "null"], "format": "date-time"}, "only_with_phone": {"type": "boolean"}, "only_paused": {"type": "boolean"}, "kanban_setting_id": {"type": ["integer", "null"]}, "kanban_stage_ids": {"type": ["array", "null"], "items": {"type": "integer"}}, "only_stagnant": {"type": ["boolean", "null"]}, "exclude_never_replied": {"type": "boolean"}, "lead_score_categories": {"type": ["array", "null"], "items": {"type": "string", "enum": ["insufficient_data", "hot", "warm", "cold"]}}, "lead_score_min": {"type": ["integer", "null"], "minimum": 0, "maximum": 100}, "lead_score_max": {"type": ["integer", "null"], "minimum": 0, "maximum": 100}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"contactsCount": {"type": "integer"}, "unreachableCount": {"type": "integer"}, "pausedCount": {"type": "integer"}, "optedOutCount": {"type": "integer"}}, "required": ["contactsCount", "unreachableCount", "pausedCount", "optedOutCount"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/broadcasts/cost-tiers": {"get": {"operationId": "broadcast.costTiers", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/cost-tiers", "tags": ["Broadcast"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BroadcastCostTiersResource"}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/broadcasts/move-to-folder": {"post": {"operationId": "broadcast.moveToFolder", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /broadcasts/move-to-folder", "tags": ["Broadcast"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MoveBroadcastsToFolderRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"moved": {"type": "integer", "minimum": 0}}, "required": ["moved"]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/broadcasts/{broadcast}": {"get": {"operationId": "broadcast.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/{broadcast}", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BroadcastResource"}}}}, "403": {"description": "Forbidden", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "No tienes permiso para ver este broadcast."}}, "required": ["message"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "delete": {"operationId": "broadcast.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /broadcasts/{broadcast}", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content"}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Las campañas que ya fueron enviadas o están saliendo no pueden eliminarse."}, "error_code": {"type": "string", "const": "broadcast_delete_not_allowed"}}, "required": ["message", "error_code"]}}}}, "403": {"description": "Forbidden", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "No tienes permiso para eliminar este broadcast."}}, "required": ["message"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/broadcasts/{broadcast}/statistics": {"get": {"operationId": "broadcast.statistics", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/{broadcast}/statistics", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"broadcast_id": {"type": "integer"}, "statistics": {"type": "object", "properties": {"delivered_messages_count": {"type": "integer"}, "readed_messages_count": {"type": "integer"}, "failed_messages_count": {"type": "integer"}, "pending_messages_count": {}, "replied_messages_count": {"type": "integer"}, "skipped_messages_count": {"type": "number"}, "skipped_by_reason": {"type": "object", "additionalProperties": {"type": "string"}}}, "required": ["delivered_messages_count", "readed_messages_count", "failed_messages_count", "pending_messages_count", "replied_messages_count", "skipped_messages_count", "skipped_by_reason"]}, "button_interactions": {"type": "array", "items": {"type": "object", "properties": {"button_index": {"type": "integer"}, "clicks_count": {"type": "integer"}}, "required": ["button_index", "clicks_count"]}}}, "required": ["broadcast_id", "statistics", "button_interactions"]}, {"type": "object", "properties": {"broadcast_id": {"type": "integer"}, "statistics": {"type": "object", "properties": {"delivered_messages_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "readed_messages_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "failed_messages_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "pending_messages_count": {}, "replied_messages_count": {"type": "integer"}, "skipped_messages_count": {"type": "number"}, "skipped_by_reason": {"type": "object", "additionalProperties": {"type": "string"}}}, "required": ["delivered_messages_count", "readed_messages_count", "failed_messages_count", "pending_messages_count", "replied_messages_count", "skipped_messages_count", "skipped_by_reason"]}, "button_interactions": {"type": "array", "items": {"type": "object", "properties": {"button_index": {"type": "integer"}, "clicks_count": {"type": "integer"}}, "required": ["button_index", "clicks_count"]}}}, "required": ["broadcast_id", "statistics", "button_interactions"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/broadcasts/{broadcast}/cost": {"get": {"operationId": "broadcast.cost", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/{broadcast}/cost", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BroadcastCostResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/broadcasts/{broadcast}/contacts": {"get": {"operationId": "broadcast.broadcastContacts", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/{broadcast}/contacts", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/broadcasts/{broadcast}/cancel": {"post": {"operationId": "broadcast.cancel", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /broadcasts/{broadcast}/cancel", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Broadcast cancelled."}}, "required": ["message"]}}}}, "409": {"description": "Conflict", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Ese envío ya fue reanudado o cancelado."}, "error_code": {"type": "string", "const": "smart_send_already_transitioned"}}, "required": ["message", "error_code"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/broadcasts/{broadcast}/messages": {"get": {"operationId": "broadcast.broadcastMessages", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/{broadcast}/messages", "tags": ["Broadcast"], "parameters": [{"name": "broadcast", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "status[]", "in": "query", "required": true, "schema": {"type": "array", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], "items": {"type": "string", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]}}}, {"name": "tab", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "delivered", "read", "replied", "failed", "skipped", null]}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/BroadcastMessageResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/broadcasts/folders": {"get": {"operationId": "broadcastFolder.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /broadcasts/folders", "tags": ["BroadcastFolder"], "parameters": [{"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/BroadcastFolderResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "broadcastFolder.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /broadcasts/folders", "tags": ["BroadcastFolder"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreBroadcastFolderRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BroadcastFolderResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/broadcasts/folders/{broadcastFolder}": {"put": {"operationId": "broadcastFolder.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /broadcasts/folders/{broadcastFolder}", "tags": ["BroadcastFolder"], "parameters": [{"name": "broadcastFolder", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateBroadcastFolderRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BroadcastFolderResource"}}}}, "403": {"description": "Forbidden", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "You do not have permission to edit this folder."}}, "required": ["message"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "broadcastFolder.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /broadcasts/folders/{broadcastFolder}", "tags": ["BroadcastFolder"], "parameters": [{"name": "broadcastFolder", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content"}, "403": {"description": "Forbidden", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "You do not have permission to delete this folder."}}, "required": ["message"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts": {"get": {"operationId": "contact.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts", "tags": ["Contact"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "email", "in": "query", "schema": {"type": "string"}}, {"name": "phone", "in": "query", "schema": {"type": "string"}}, {"name": "whatsapp_id", "in": "query", "schema": {"type": "string"}}, {"name": "country_codes[]", "in": "query", "schema": {"type": "array", "items": {"type": "string"}}}, {"name": "status", "in": "query", "schema": {"type": "string"}}, {"name": "image", "in": "query", "schema": {"type": "string"}}, {"name": "created_at", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "created_from", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "created_to", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "tag_ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "tag_mode", "in": "query", "schema": {"type": "string", "enum": ["all", "any", "exclude"]}}, {"name": "custom_field_ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "custom_field_mode", "in": "query", "schema": {"type": "string", "enum": ["all", "any", "exclude"]}}, {"name": "custom_field_value", "in": "query", "schema": {"type": "string"}}, {"name": "custom_field_date_from", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "custom_field_date_to", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "custom_field_numeric_operator", "in": "query", "schema": {"type": "string", "enum": ["lt", "eq", "gt"]}}, {"name": "custom_field_numeric_value", "in": "query", "schema": {"type": "number"}}, {"name": "only_with_phone", "in": "query", "schema": {"type": "string"}}, {"name": "only_with_mac", "in": "query", "schema": {"type": "string"}}, {"name": "scopeToAdvisor", "in": "query", "schema": {"type": "string"}}, {"name": "lead_score_categories[]", "in": "query", "schema": {"type": "array", "enum": ["insufficient_data", "hot", "warm", "cold"], "items": {"type": "string", "enum": ["insufficient_data", "hot", "warm", "cold"]}}}, {"name": "lead_score_min", "in": "query", "schema": {"type": "integer", "minimum": 0, "maximum": 100}}, {"name": "lead_score_max", "in": "query", "schema": {"type": "integer", "minimum": 0, "maximum": 100}}, {"name": "lead_score_disqualified", "in": "query", "schema": {"type": ["string", "null"], "enum": ["include", "exclude", "only", null]}}, {"name": "tag_filters", "in": "query", "schema": {"type": "array", "items": {"type": "object", "properties": {"mode": {"type": "string", "enum": ["all", "any", "exclude"]}, "tag_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["mode"]}}, "x-deepObject-style": "qs"}, {"name": "custom_field_filters", "in": "query", "schema": {"type": "array", "items": {"type": "object", "properties": {"type": {"type": "integer", "enum": ["0", "1", "2", "3", "4"]}, "mode": {"type": ["string", "null"], "enum": ["all", "any", "exclude", null]}, "value": {"type": ["string", "null"]}, "date_from": {"type": ["string", "null"], "format": "date"}, "date_to": {"type": ["string", "null"], "format": "date"}, "numeric_operator": {"type": ["string", "null"], "enum": ["lt", "eq", "gt", null]}, "numeric_value": {"type": ["number", "null"]}, "date_operator": {"type": ["string", "null"], "enum": ["lt", "gt", "eq", "period", null]}, "custom_field_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["type"]}}, "x-deepObject-style": "qs"}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["id", "name", "email", "phone", "status", "favorite", "unread_messages", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ContactResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "contact.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts", "tags": ["Contact"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreContactRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactResource"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/update-or-create": {"post": {"operationId": "contact.updateOrCreate", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/update-or-create", "tags": ["Contact"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"phone": {"type": "string"}, "name": {"type": ["string", "null"]}, "email": {"type": ["string", "null"], "format": "email"}}, "required": ["phone"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactResource"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Contacto no encontrado."}}, "required": ["message"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/attach-custom-field": {"post": {"operationId": "contact.attachCustomField", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/attach-custom-field", "tags": ["Contact"], "requestBody": {"content": {"application/json": {"schema": {"type": "array", "items": {"type": "object", "properties": {"customFieldId": {"type": "integer"}, "contactId": {"type": "integer"}, "value": {"type": "string"}}, "required": ["customFieldId", "contactId", "value"]}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "array", "items": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string", "const": "No autorizado: el campo personalizado no pertenece al usuario autenticado."}, "status": {"type": "integer", "const": 403}}, "required": ["message", "status"]}, {"type": "object", "properties": {"message": {"type": "string", "const": "No autorizado: el contacto no pertenece al usuario autenticado."}, "status": {"type": "integer", "const": 403}}, "required": ["message", "status"]}, {"type": "object", "properties": {"message": {"type": "string", "const": "Custom field value attached successfully."}, "status": {"type": "integer", "const": 201}}, "required": ["message", "status"]}]}}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/detach-custom-field": {"post": {"operationId": "contact.detachCustomField", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/detach-custom-field", "tags": ["Contact"], "requestBody": {"content": {"application/json": {"schema": {"type": "array", "items": {"type": "object", "properties": {"customFieldId": {"type": "integer"}, "contactId": {"type": "integer"}}, "required": ["customFieldId", "contactId"]}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"messages": {"type": "array", "items": {"type": "string"}}}, "required": ["messages"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}": {"get": {"operationId": "contact.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}", "tags": ["Contact"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/ContactResource"}, {"type": "object", "required": ["whatsapp_username", "custom_fields", "manually_unread", "name_mismatch"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "contact.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /contacts/{contact}", "tags": ["Contact"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateContactRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/tags": {"get": {"operationId": "contact.tags", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/tags", "tags": ["Contact"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ContactTagResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/{contact}/custom-fields": {"get": {"operationId": "contact.customFields", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/custom-fields", "tags": ["Contact"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ContactCustomFieldResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/{contact}/meta-window": {"get": {"operationId": "contact.metaWindow", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/meta-window", "tags": ["Contact"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "device_id", "in": "query", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"is_open": {"type": "boolean"}, "meta_device_id": {"type": "null"}, "expires_at": {"type": "null"}}, "required": ["is_open", "meta_device_id", "expires_at"]}, {"type": "object", "properties": {"is_open": {"type": "boolean"}, "meta_device_id": {"type": "null"}, "expires_at": {"type": ["string", "null"]}}, "required": ["is_open", "meta_device_id", "expires_at"]}, {"type": "object", "properties": {"is_open": {"type": "boolean"}, "meta_device_id": {}, "expires_at": {"type": ["string", "null"]}}, "required": ["is_open", "meta_device_id", "expires_at"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/devices/{device}/contacts": {"get": {"operationId": "contact.contactsByDevice", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /devices/{device}/contacts", "tags": ["Contact"], "parameters": [{"name": "device", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/ContactResource"}, {"type": "object", "required": ["whatsapp_username"]}]}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/delete": {"post": {"operationId": "contact.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/delete", "tags": ["Contact"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"all": {"type": "boolean"}, "contactIds": {"type": "array", "items": {"type": "integer"}}, "created_from": {"type": ["string", "null"], "format": "date-time"}, "created_to": {"type": ["string", "null"], "format": "date-time"}, "tag_mode": {"type": ["string", "null"], "enum": ["all", "any", "exclude", null]}, "tag_ids": {"type": ["array", "null"], "items": {"type": "integer"}}, "tag_filters": {"type": ["array", "null"], "items": {"type": "object", "properties": {"tag_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1}, "mode": {"type": "string", "enum": ["all", "any", "exclude"]}}, "required": ["tag_ids", "mode"]}}, "custom_field_mode": {"type": ["string", "null"], "enum": ["all", "any", "exclude", null]}, "custom_field_ids": {"type": ["array", "null"], "items": {"type": "integer"}}, "custom_field_value": {"type": ["string", "null"]}, "custom_field_date_from": {"type": ["string", "null"], "format": "date"}, "custom_field_date_to": {"type": ["string", "null"], "format": "date"}, "custom_field_numeric_operator": {"type": ["string", "null"], "enum": ["lt", "eq", "gt", null]}, "custom_field_numeric_value": {"type": ["number", "null"]}, "custom_field_filters": {"type": ["array", "null"], "items": {"type": "object", "properties": {"custom_field_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1}, "type": {"type": "integer", "enum": ["0", "1", "2", "3", "4"]}, "mode": {"type": ["string", "null"], "enum": ["all", "any", "exclude", null]}, "value": {"type": ["string", "null"]}, "date_from": {"type": ["string", "null"], "format": "date"}, "date_to": {"type": ["string", "null"], "format": "date"}, "numeric_operator": {"type": ["string", "null"], "enum": ["lt", "eq", "gt", null]}, "numeric_value": {"type": ["number", "null"]}, "date_operator": {"type": ["string", "null"], "enum": ["lt", "gt", "eq", "period", null]}}, "required": ["custom_field_ids", "type"]}}, "country_codes": {"type": "array", "items": {"type": "string"}}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/pause": {"post": {"operationId": "contactAutomation.pause", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/{contact}/pause", "tags": ["ContactAutomation"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/flows": {"get": {"operationId": "contactAutomation.flows", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/flows", "tags": ["ContactAutomation"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ContactFlowListResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/{contact}/message/contact-card": {"post": {"operationId": "contactCard.store", "description": "**Permiso requerido:** `conversations:send`", "summary": "POST /contacts/{contact}/message/contact-card", "tags": ["ContactCard"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreContactCardRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"messages": {"type": "array", "items": {"$ref": "#/components/schemas/PublicMessageResource"}}}, "required": ["messages"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["window_closed", "antiblock_duplicate_content", "antiblock_unanswered_limit", "recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["device_unavailable", "not_sent"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "enum": ["Server Error"]}}, "required": ["message"]}}}}}, "x-fc-permission": "conversations:send"}}, "/contacts/{contact}/lead-score": {"get": {"operationId": "contactLeadScore.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/lead-score", "tags": ["ContactLeadScore"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactLeadScoreResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/{contact}/notes": {"get": {"operationId": "contactNote.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/notes", "tags": ["ContactNote"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "search", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 255}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ContactNoteResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "contactNote.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/{contact}/notes", "tags": ["ContactNote"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreContactNoteRequest"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ContactNoteResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/notes/{note}": {"delete": {"operationId": "contactNote.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /contacts/{contact}/notes/{note}", "tags": ["ContactNote"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "note", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/conversations": {"get": {"operationId": "conversation.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /conversations", "tags": ["Conversation"], "parameters": [{"name": "favorites", "in": "query", "schema": {"type": "boolean"}}, {"name": "ownContacts", "in": "query", "schema": {"type": "boolean"}}, {"name": "ownAndUnassigned", "in": "query", "schema": {"type": "boolean"}}, {"name": "perName", "in": "query", "schema": {"type": "string"}}, {"name": "deviceId", "in": "query", "schema": {"type": "integer"}}, {"name": "contactId", "in": "query", "schema": {"type": "integer"}}, {"name": "advisorId", "in": "query", "schema": {"type": "integer"}}, {"name": "advisorIds", "in": "query", "schema": {"type": "string"}}, {"name": "activeConversation", "in": "query", "schema": {"type": "boolean"}}, {"name": "tags", "in": "query", "schema": {"type": "string"}}, {"name": "kanbanSettingId", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "kanbanStageIds", "in": "query", "schema": {"type": "string"}}, {"name": "unreadMessages", "in": "query", "schema": {"type": "boolean"}}, {"name": "onlyWithMac", "in": "query", "schema": {"type": "boolean"}}, {"name": "cursor", "in": "query", "schema": {"type": "string"}}, {"name": "updated_since", "in": "query", "schema": {"type": "string"}}, {"name": "paused", "in": "query", "schema": {"type": "string", "enum": ["true", "false", "1", "0"]}}, {"name": "leadScoreCategories", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "leadScoreMin", "in": "query", "schema": {"type": "integer", "minimum": 0, "maximum": 100}}, {"name": "leadScoreMax", "in": "query", "schema": {"type": "integer", "minimum": 0, "maximum": 100}}, {"name": "leadScoreDisqualified", "in": "query", "schema": {"type": ["string", "null"], "enum": ["include", "exclude", "only", null]}}, {"name": "metaWindowOpen", "in": "query", "schema": {"type": "boolean"}}, {"name": "metaWindowDeviceIds", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "lastMessageDateFrom", "in": "query", "schema": {"type": ["string", "null"], "format": "date"}}, {"name": "lastMessageDateTo", "in": "query", "schema": {"type": ["string", "null"], "format": "date"}}, {"name": "timezone", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "customFieldFilters", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "const": "No se pudieron cargar las conversaciones"}}, "required": ["error"]}}}}, "200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"is_mac_inactive": {"type": "boolean", "description": "`true` si el contacto es inactivo por el límite de contactos activos en el momento de la consulta: tu cuenta está en bloqueo (`state` = `enforcing` en `GET /mac/status`) y el contacto todavía no es un contacto activo del ciclo actual. Viene en `GET /contacts`, `GET /contacts/{contact}` y `GET /conversations`."}}, "required": ["is_mac_inactive"]}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"path": {"type": "string"}, "per_page": {"type": "integer"}, "next_cursor": {"type": ["string", "null"]}, "prev_cursor": {"type": ["string", "null"]}}, "required": ["path", "per_page", "next_cursor", "prev_cursor"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/conversations/count/unread": {"get": {"operationId": "conversation.countUnread", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /conversations/count/unread", "tags": ["Conversation"], "parameters": [{"name": "advisorIds", "in": "query", "schema": {"type": "string"}}, {"name": "favorites", "in": "query", "schema": {"type": "boolean"}}, {"name": "ownAndUnassigned", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"count": {"type": "integer", "minimum": 0}}, "required": ["count"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/conversations/count/open": {"get": {"operationId": "conversation.countOpen", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /conversations/count/open", "tags": ["Conversation"], "parameters": [{"name": "advisorIds", "in": "query", "schema": {"type": "string"}}, {"name": "favorites", "in": "query", "schema": {"type": "boolean"}}, {"name": "ownAndUnassigned", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"count": {"type": "integer", "minimum": 0}}, "required": ["count"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/conversations/count/closed": {"get": {"operationId": "conversation.countClosed", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /conversations/count/closed", "tags": ["Conversation"], "parameters": [{"name": "advisorIds", "in": "query", "schema": {"type": "string"}}, {"name": "favorites", "in": "query", "schema": {"type": "boolean"}}, {"name": "ownAndUnassigned", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"count": {"type": "integer", "minimum": 0}}, "required": ["count"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/conversations/count/all": {"get": {"operationId": "conversation.countAll", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /conversations/count/all", "tags": ["Conversation"], "parameters": [{"name": "advisorIds", "in": "query", "schema": {"type": "string"}}, {"name": "favorites", "in": "query", "schema": {"type": "boolean"}}, {"name": "ownAndUnassigned", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"count": {"type": "integer", "minimum": 0}}, "required": ["count"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/conversations/mark-all-read": {"post": {"operationId": "conversation.markAllAsRead", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /conversations/mark-all-read", "tags": ["Conversation"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"advisorIds": {"type": "string"}, "favorites": {"type": "boolean"}, "ownAndUnassigned": {"type": "boolean"}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Todas las conversaciones han sido marcadas como leídas"}, "updated_count": {"type": "integer"}}, "required": ["message", "updated_count"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/conversations/mark-all-unread": {"post": {"operationId": "conversation.markAllAsUnread", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /conversations/mark-all-unread", "tags": ["Conversation"], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"advisorIds": {"type": "string"}, "favorites": {"type": "boolean"}, "ownAndUnassigned": {"type": "boolean"}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Todas las conversaciones elegibles fueron marcadas como no leídas"}, "marked_count": {"type": "integer"}, "limit_reached": {"type": "boolean"}, "contact_ids": {"type": "object", "additionalProperties": {}}}, "required": ["message", "marked_count", "limit_reached", "contact_ids"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/update": {"put": {"operationId": "conversation.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /contacts/{contact}/update", "tags": ["Conversation"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"favorite": {"type": "boolean"}, "active_conversation": {"type": "boolean"}, "unread_messages": {"type": "integer"}, "adviser_id": {"type": ["integer", "null"]}, "device_id": {"type": "integer"}, "text": {"type": "string"}, "notes": {"type": ["string", "null"]}, "custom_fields": {"type": "array", "items": {"type": "string"}}, "manually_unread": {"type": "boolean"}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/message": {"post": {"operationId": "conversation.sendMessage", "description": "**Permiso requerido:** `conversations:send`", "summary": "POST /contacts/{contact}/message", "tags": ["Conversation"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SendMessageRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"anyOf": [{"$ref": "#/components/schemas/PublicMessageResource"}, {"type": "null"}]}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["window_closed", "antiblock_duplicate_content", "antiblock_unanswered_limit", "recipient_mismatch", "recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["device_unavailable", "not_sent"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "enum": ["Server Error"]}}, "required": ["message"]}}}}}, "x-fc-permission": "conversations:send"}}, "/contacts/{contactId}/messages": {"get": {"operationId": "conversation.getLatestMessages", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contactId}/messages", "tags": ["Conversation"], "parameters": [{"name": "contactId", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "cursor", "in": "query", "schema": {"type": "string"}}, {"name": "updated_since", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/MessageResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"path": {"type": "string"}, "per_page": {"type": "integer"}, "next_cursor": {"type": ["string", "null"]}, "prev_cursor": {"type": ["string", "null"]}}, "required": ["path", "per_page", "next_cursor", "prev_cursor"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/custom-fields": {"get": {"operationId": "customField.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /custom-fields", "tags": ["CustomField"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "description", "in": "query", "schema": {"type": "string"}}, {"name": "type", "in": "query", "schema": {"type": "integer"}}, {"name": "withContactCount", "in": "query", "schema": {"type": "boolean"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/CustomFieldResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "customField.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /custom-fields", "tags": ["CustomField"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 254}, "description": {"type": ["string", "null"], "maxLength": 1000}, "type": {"type": "integer"}}, "required": ["name", "type"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomFieldResource"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/custom-fields/delete": {"post": {"operationId": "customField.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /custom-fields/delete", "tags": ["CustomField"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"customFieldIds": {"type": "array", "items": {"type": "string"}, "minItems": 1}}, "required": ["customFieldIds"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/custom-fields/{customField}": {"get": {"operationId": "customField.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /custom-fields/{customField}", "tags": ["CustomField"], "parameters": [{"name": "customField", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomFieldResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "customField.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /custom-fields/{customField}", "tags": ["CustomField"], "parameters": [{"name": "customField", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 254}, "description": {"type": ["string", "null"], "maxLength": 1000}}}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomFieldResource"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contact-flows/{contactId}": {"get": {"operationId": "flow.contactFlowHistory", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contact-flows/{contactId}", "tags": ["Flow"], "parameters": [{"name": "contactId", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "search", "in": "query", "schema": {"type": "string", "maxLength": 255}}, {"name": "status_group", "in": "query", "schema": {"type": "string", "enum": ["en_curso", "completado", "invalidado", "cancelado"]}}, {"name": "date_from", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "date_to", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/contact-flows/{contactFlowId}/cancel": {"put": {"operationId": "flow.cancelContactFlow", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /contact-flows/{contactFlowId}/cancel", "tags": ["Flow"], "parameters": [{"name": "contactFlowId", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"contact_flow": {"type": "object", "properties": {"id": {"type": "integer"}, "status": {"type": "integer"}}, "required": ["id", "status"]}}, "required": ["contact_flow"]}}}}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "No se puede cancelar esta automatización. Puede que ya haya finalizado o no exista."}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/flows": {"get": {"operationId": "flow.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /flows", "tags": ["Flow"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "folder_id", "in": "query", "schema": {"type": "integer"}}, {"name": "unclassified", "in": "query", "schema": {"type": "string"}}, {"name": "trigger_type", "in": "query", "schema": {"type": "string", "enum": ["1", "2", "3", "4", "5", "6", "7", "inbound_automation"]}}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["active", "inactive"]}}, {"name": "date_from", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "date_to", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "date_field", "in": "query", "schema": {"type": "string", "enum": ["created_at", "updated_at"]}}, {"name": "device_id", "in": "query", "schema": {"type": "string"}}, {"name": "device_ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer", "minimum": 1}}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/FlowResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/flows/{flow}": {"get": {"operationId": "flow.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /flows/{flow}", "tags": ["Flow"], "parameters": [{"name": "flow", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/FlowResource"}, {"type": "object", "required": ["folder"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/flows/{flow}/nodes": {"get": {"operationId": "flow.nodes", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /flows/{flow}/nodes", "tags": ["Flow"], "parameters": [{"name": "flow", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/NodeResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/flows/{flow}/active-contacts": {"get": {"operationId": "flow.activeContacts", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /flows/{flow}/active-contacts", "tags": ["Flow"], "parameters": [{"name": "flow", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "payment_event_type", "in": "query", "schema": {"type": "string", "enum": ["approved", "pending", "rejected", "cancelled", "refunded", "chargeback"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"active_contacts_count": {"type": "integer", "minimum": 0}}, "required": ["active_contacts_count"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/flows/{flow}/active-contacts-list": {"get": {"operationId": "flow.activeContactsList", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /flows/{flow}/active-contacts-list", "tags": ["Flow"], "parameters": [{"name": "flow", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "search", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/flows/{flow}/flow-contacts": {"get": {"operationId": "flow.flowContactsList", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /flows/{flow}/flow-contacts", "tags": ["Flow"], "parameters": [{"name": "flow", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "search", "in": "query", "schema": {"type": "string", "maxLength": 255}}, {"name": "status_group", "in": "query", "schema": {"type": "string", "enum": ["en_curso", "completado", "invalidado", "cancelado"]}}, {"name": "date_from", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "date_to", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/folders": {"get": {"operationId": "folder.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /folders", "tags": ["Folder"], "parameters": [{"name": "name", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 255}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/FolderResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "folder.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /folders", "tags": ["Folder"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreFolderRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FolderResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/folders/{folder}": {"get": {"operationId": "folder.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /folders/{folder}", "tags": ["Folder"], "parameters": [{"name": "folder", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/FolderResource"}, {"type": "object", "required": ["children"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "folder.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /folders/{folder}", "tags": ["Folder"], "parameters": [{"name": "folder", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateFolderRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "folder.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /folders/{folder}", "tags": ["Folder"], "parameters": [{"name": "folder", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/messages/{message}/forward": {"post": {"operationId": "forwardMessage.store", "description": "**Permiso requerido:** `conversations:send`", "summary": "POST /contacts/{contact}/messages/{message}/forward", "tags": ["ForwardMessage"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "message", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ForwardMessageRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "array", "items": {"type": "object", "properties": {"contact_id": {"type": "integer"}, "mode": {"type": "string", "enum": ["internal", "native"]}, "status": {"type": "string", "enum": ["queued", "blocked"]}, "reason": {"type": ["string", "null"]}, "message": {"anyOf": [{"$ref": "#/components/schemas/PublicMessageResource"}, {"type": "null"}]}}, "required": ["contact_id", "mode", "status", "reason", "message"]}}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["window_closed", "antiblock_duplicate_content", "antiblock_unanswered_limit", "recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["device_unavailable"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "enum": ["Server Error"]}}, "required": ["message"]}}}}}, "x-fc-permission": "conversations:send"}}, "/kanban-settings": {"get": {"operationId": "kanbanSetting.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /kanban-settings", "tags": ["KanbanSetting"], "parameters": [{"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/KanbanSettingResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "kanbanSetting.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings", "tags": ["KanbanSetting"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreKanbanSettingRequest"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KanbanSettingResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}": {"get": {"operationId": "kanbanSetting.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /kanban-settings/{kanbanSetting}", "tags": ["KanbanSetting"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/KanbanSettingResource"}, {"type": "object", "required": ["stages"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "kanbanSetting.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /kanban-settings/{kanbanSetting}", "tags": ["KanbanSetting"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateKanbanSettingRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KanbanSettingResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "kanbanSetting.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /kanban-settings/{kanbanSetting}", "tags": ["KanbanSetting"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/members": {"get": {"operationId": "kanbanSetting.members", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /kanban-settings/{kanbanSetting}/members", "tags": ["KanbanSetting"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "contact_ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"member_contact_ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["member_contact_ids"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/{contact}/kanban-stages": {"get": {"operationId": "kanbanStage.contactStages", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /contacts/{contact}/kanban-stages", "tags": ["KanbanStage"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ContactKanbanStageBoardResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/kanban-settings/{kanbanSetting}/move-contact": {"post": {"operationId": "kanbanStage.moveContact", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings/{kanbanSetting}/move-contact", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MoveContactStageRequest"}}}}, "responses": {"200": {"description": "OK"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/bulk-move": {"post": {"operationId": "kanbanStage.bulkMove", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings/{kanbanSetting}/bulk-move", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BulkMoveStageRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": ["object", "null"], "properties": {"excluded_inactive": {"type": "integer", "description": "Cantidad de contactos inactivos que no se movieron. El cuerpo es `null` cuando no se dejó afuera a ninguno.", "minimum": 1}}, "required": ["excluded_inactive"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/remove-contact": {"post": {"operationId": "kanbanStage.removeContact", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings/{kanbanSetting}/remove-contact", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RemoveContactStageRequest"}}}}, "responses": {"200": {"description": "OK"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/bulk-remove": {"post": {"operationId": "kanbanStage.bulkRemove", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings/{kanbanSetting}/bulk-remove", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BulkRemoveStageRequest"}}}}, "responses": {"200": {"description": "OK"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/stages": {"post": {"operationId": "kanbanStage.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings/{kanbanSetting}/stages", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreKanbanStageRequest"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KanbanStageResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/stages/reorder": {"post": {"operationId": "kanbanStage.reorder", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /kanban-settings/{kanbanSetting}/stages/reorder", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ReorderKanbanStagesRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/KanbanStageResource"}}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/stages/{stage}": {"put": {"operationId": "kanbanStage.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /kanban-settings/{kanbanSetting}/stages/{stage}", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "stage", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateKanbanStageRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/KanbanStageResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "kanbanStage.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /kanban-settings/{kanbanSetting}/stages/{stage}", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "stage", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "reassign_to_stage_id", "in": "query", "schema": {"type": ["integer", "null"]}}], "responses": {"204": {"description": "No Content"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/kanban-settings/{kanbanSetting}/stages/{stage}/contacts": {"get": {"operationId": "kanbanStage.contacts", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /kanban-settings/{kanbanSetting}/stages/{stage}/contacts", "tags": ["KanbanStage"], "parameters": [{"name": "kanbanSetting", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "stage", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "search", "in": "query", "schema": {"type": "string"}}, {"name": "messages", "in": "query", "schema": {"type": "string", "enum": ["all", "read", "unread"]}}, {"name": "dateFrom", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "dateTo", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "dateBasis", "in": "query", "schema": {"type": "string", "enum": ["board_entry", "created", "last_activity"]}}, {"name": "adviserId", "in": "query", "schema": {"type": "string"}}, {"name": "valueMin", "in": "query", "schema": {"type": "number"}}, {"name": "valueMax", "in": "query", "schema": {"type": "number"}}, {"name": "stagnant", "in": "query", "schema": {"type": "boolean"}}, {"name": "tagIds[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "leadScoreCategories[]", "in": "query", "schema": {"type": "array", "enum": ["insufficient_data", "hot", "warm", "cold"], "items": {"type": "string", "enum": ["insufficient_data", "hot", "warm", "cold"]}}}, {"name": "leadScoreMin", "in": "query", "schema": {"type": "integer", "minimum": 0, "maximum": 100}}, {"name": "leadScoreMax", "in": "query", "schema": {"type": "integer", "minimum": 0, "maximum": 100}}, {"name": "leadScoreDisqualified", "in": "query", "schema": {"type": ["string", "null"], "enum": ["include", "exclude", "only", null]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "last_message_time", "stage_since"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/lead-score/distribution": {"get": {"operationId": "leadScoreDistribution.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /lead-score/distribution", "tags": ["LeadScoreDistribution"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadScoreDistributionResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/lead-score/events": {"post": {"operationId": "leadScoreEventIngest.ingest", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /lead-score/events", "tags": ["LeadScoreEventIngest"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IngestLeadScoreEventsRequest"}}}}, "responses": {"202": {"description": "Accepted", "content": {"application/json": {"schema": {"type": "object", "properties": {"success": {"type": "boolean"}}, "required": ["success"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/lead-score/settings": {"get": {"operationId": "leadScoreSettings.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /lead-score/settings", "tags": ["LeadScoreSettings"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadScoreSettingsResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "leadScoreSettings.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /lead-score/settings", "tags": ["LeadScoreSettings"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LeadScoreSettingsResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/lead-score/adjustments": {"post": {"operationId": "leadScoreSettings.adjust", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /contacts/{contact}/lead-score/adjustments", "tags": ["LeadScoreSettings"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreLeadScoreAdjustmentRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"score": {"type": "integer"}, "signals_count": {"type": "integer"}, "category": {"type": "string"}, "confidence": {"type": "string"}, "disqualified": {"type": "boolean"}, "disqualified_at": {"type": ["string", "null"]}}, "required": ["score", "signals_count", "category", "confidence", "disqualified", "disqualified_at"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/mac/status": {"get": {"operationId": "mac.status", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /mac/status", "tags": ["Mac"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"enforcement_enabled": {"type": "boolean"}, "state": {"type": "string", "description": "Estado del límite de contactos activos de tu cuenta: `normal`; `grace`, alcanzaste el límite y corren las 24 horas de gracia; `enforcing`, bloqueo: hay contactos inactivos; `cleared`, el último período de gracia o de bloqueo ya terminó.", "enum": ["normal", "grace", "enforcing", "cleared"]}, "inactive_contacts_count": {"type": "integer", "description": "Contactos registrados como inactivos en el ciclo actual: a los que se les frenó un mensaje, que te escribieron estando inactivos o que una difusión dejó afuera. No es el total de contactos que podrían serlo: para un contacto puntual, usa `is_mac_inactive`.", "minimum": 0}}, "required": ["enforcement_enabled", "state", "inactive_contacts_count"]}, {"type": "object", "properties": {"enforcement_enabled": {"type": "boolean"}, "current_count": {"type": "integer", "const": 0}, "limit": {"type": "integer", "const": 0}, "remaining": {"type": "integer", "const": 0}, "usage_percentage": {"type": "integer", "const": 0}, "state": {"type": "string", "const": "normal"}, "grace": {"type": "null"}, "period_start": {"type": "null"}}, "required": ["enforcement_enabled", "current_count", "limit", "remaining", "usage_percentage", "state", "grace", "period_start"]}]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/mac/contacts": {"get": {"operationId": "mac.contacts", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /mac/contacts", "tags": ["Mac"], "parameters": [{"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/mac/contacts/history": {"get": {"operationId": "mac.contactsHistory", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /mac/contacts/history", "tags": ["Mac"], "parameters": [{"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/message/send-message": {"post": {"operationId": "message.sendMessage", "description": "**Permiso requerido:** `conversations:send`", "summary": "POST /message/send-message", "tags": ["Message"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SendDirectMessageRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"anyOf": [{"$ref": "#/components/schemas/PublicMessageResource"}, {"type": "null"}]}}, "required": ["message"]}}}}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["window_closed", "antiblock_duplicate_content", "antiblock_unanswered_limit", "recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["device_unavailable", "not_sent"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "enum": ["Server Error"]}}, "required": ["message"]}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"type": "object", "properties": {"status": {"type": "string", "enum": ["error"]}, "error": {"type": "string"}}, "required": ["status", "error"]}}}}}, "x-fc-permission": "conversations:send"}}, "/contacts/{contact}/messages/{message}/reaction": {"put": {"operationId": "messageReaction.update", "description": "**Permiso requerido:** `conversations:send`", "summary": "PUT /contacts/{contact}/messages/{message}/reaction", "tags": ["MessageReaction"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "message", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreMessageReactionRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}}, "x-fc-permission": "conversations:send"}, "delete": {"operationId": "messageReaction.destroy", "description": "**Permiso requerido:** `conversations:send`", "summary": "DELETE /contacts/{contact}/messages/{message}/reaction", "tags": ["MessageReaction"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "message", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object"}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}}, "x-fc-permission": "conversations:send"}}, "/templates": {"get": {"operationId": "messageTemplate.templates", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /templates", "tags": ["MessageTemplate"], "parameters": [{"name": "name", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "uid", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "language_code", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "status", "in": "query", "schema": {"type": ["string", "null"], "enum": ["PENDING", "APPROVED", "REJECTED", "PENDING_DELETION", "PAUSED", "DISABLED", "ARCHIVED", null]}}, {"name": "category", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "deviceId", "in": "query", "schema": {"type": ["integer", "null"]}}, {"name": "type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["text", "image", "document", "video", "location", "default", null]}}, {"name": "created_by_webhook", "in": "query", "schema": {"type": "boolean"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/TemplateResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "messageTemplate.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /templates", "tags": ["MessageTemplate"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreMessageTemplateRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TemplateResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/templates/{template}": {"put": {"operationId": "messageTemplate.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /templates/{template}", "tags": ["MessageTemplate"], "parameters": [{"name": "template", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateMessageTemplateRequest"}}}}, "responses": {"204": {"description": "No Content"}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"error": {"type": "string", "const": "Approved templates can be edited up to 10 times in a 30-day period or once in a 24-hour period."}}, "required": ["error"]}, {"type": "object", "properties": {"error": {"type": "string", "const": "Templates with pending status cannot be updated."}}, "required": ["error"]}]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}, "get": {"operationId": "messageTemplate.template", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /templates/{template}", "tags": ["MessageTemplate"], "parameters": [{"name": "template", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TemplateResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/templates/{template}/quick-reply-buttons": {"get": {"operationId": "messageTemplate.quickReplyButtons", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /templates/{template}/quick-reply-buttons", "tags": ["MessageTemplate"], "parameters": [{"name": "template", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {}}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/devices/{device}/templates/{template}/send-template": {"post": {"operationId": "messageTemplate.send", "description": "**Permiso requerido:** `conversations:send`", "summary": "POST /devices/{device}/templates/{template}/send-template", "tags": ["MessageTemplate"], "parameters": [{"name": "device", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "template", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"phone": {"type": "string"}, "contact_id": {"type": "integer"}, "template_variables": {"type": "object", "properties": {"body": {"type": "array", "items": {"type": ["string", "null"], "maxLength": 1024}, "maxItems": 100}}}, "client_reference": {"type": ["string", "null"], "pattern": "^[\\x21-\\x7E]{1,64}$", "maxLength": 64}}, "required": ["phone", "contact_id"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"anyOf": [{"$ref": "#/components/schemas/PublicMessageResource"}, {"type": "null"}]}}, "required": ["message"]}}}}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["antiblock_duplicate_content", "antiblock_unanswered_limit", "recipient_mismatch", "recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["device_unavailable", "not_sent"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["template_unresolved_placeholder"]}, "message": {"type": "string"}, "placeholders": {"type": "array", "items": {"type": "string"}}, "count": {"type": "integer"}}, "required": ["error", "message", "placeholders", "count"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"error": {"type": "string", "enum": ["template_not_found"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["Contact not found"]}}, "required": ["error"]}, {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}]}}}}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "enum": ["Server Error"]}}, "required": ["message"]}}}}}, "x-fc-permission": "conversations:send"}}, "/devices/{device}/templates/{template}": {"delete": {"operationId": "messageTemplate.delete", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /devices/{device}/templates/{template}", "tags": ["MessageTemplate"], "parameters": [{"name": "device", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "template", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/payments/products/{platform}": {"get": {"operationId": "paymentProduct.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /payments/products/{platform}", "tags": ["PaymentProduct"], "parameters": [{"name": "platform", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/PaymentProductResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/quick-replies": {"get": {"operationId": "quickReply.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /quick-replies", "tags": ["QuickReply"], "parameters": [{"name": "search", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/QuickReplyResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "quickReply.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /quick-replies", "tags": ["QuickReply"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 30}, "message": {"type": ["string", "null"], "maxLength": 2500}, "file": {"type": ["string", "null"]}, "type": {"$ref": "#/components/schemas/MessageTypeEnum"}, "visibility": {"$ref": "#/components/schemas/QuickReplyVisibilityEnum"}, "agent_ids": {"type": ["array", "null"], "items": {"type": "integer"}}}, "required": ["name", "type", "visibility"]}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QuickReplyResource"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/quick-replies/{quickReply}": {"get": {"operationId": "quickReply.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /quick-replies/{quickReply}", "tags": ["QuickReply"], "parameters": [{"name": "quickReply", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QuickReplyResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "quickReply.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /quick-replies/{quickReply}", "tags": ["QuickReply"], "parameters": [{"name": "quickReply", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 30}, "message": {"type": ["string", "null"], "maxLength": 2500}, "file": {"type": ["string", "null"]}, "type": {"$ref": "#/components/schemas/MessageTypeEnum"}, "visibility": {"$ref": "#/components/schemas/QuickReplyVisibilityEnum"}, "agent_ids": {"type": ["array", "null"], "items": {"type": "integer"}}}, "required": ["name", "type", "visibility"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QuickReplyResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "quickReply.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "DELETE /quick-replies/{quickReply}", "tags": ["QuickReply"], "parameters": [{"name": "quickReply", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/sales/metrics": {"get": {"operationId": "salesDashboard.metrics", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /sales/metrics", "tags": ["SalesDashboard"], "parameters": [{"name": "window", "in": "query", "schema": {"type": "integer", "enum": ["7", "30", "90"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "event_type[]", "in": "query", "schema": {"type": "array", "items": {"$ref": "#/components/schemas/PaymentEventTypeEnum"}}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SalesMetricsResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/sales/funnel": {"get": {"operationId": "salesDashboard.funnel", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /sales/funnel", "tags": ["SalesDashboard"], "parameters": [{"name": "window", "in": "query", "schema": {"type": "integer", "enum": ["7", "30", "90"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "event_type[]", "in": "query", "schema": {"type": "array", "items": {"$ref": "#/components/schemas/PaymentEventTypeEnum"}}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"conversations": {"type": "integer", "minimum": 0}, "qualified": {"type": ["integer", "null"], "minimum": 0}, "purchases": {"type": "object", "properties": {"buyers": {"type": "integer", "minimum": 0}, "amounts": {"type": "array", "items": {}}}, "required": ["buyers", "amounts"]}}, "required": ["conversations", "qualified", "purchases"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/sales/by-platform": {"get": {"operationId": "salesDashboard.byPlatform", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /sales/by-platform", "tags": ["SalesDashboard"], "parameters": [{"name": "window", "in": "query", "schema": {"type": "integer", "enum": ["7", "30", "90"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "event_type[]", "in": "query", "schema": {"type": "array", "items": {"$ref": "#/components/schemas/PaymentEventTypeEnum"}}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"platforms": {"type": "array", "items": {"type": "object", "properties": {"platform": {"type": "string"}, "connected": {"type": "boolean"}, "totals": {"type": "array", "items": {"type": "object", "properties": {"currency": {"type": "string"}, "total_minor": {"type": "integer"}}, "required": ["currency", "total_minor"]}}}, "required": ["platform", "connected", "totals"]}}}, "required": ["platforms"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/sales": {"get": {"operationId": "salesDashboard.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /sales", "tags": ["SalesDashboard"], "parameters": [{"name": "window", "in": "query", "schema": {"type": "integer", "enum": ["7", "30", "90"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "event_type[]", "in": "query", "schema": {"type": "array", "items": {"$ref": "#/components/schemas/PaymentEventTypeEnum"}}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/SaleResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/contacts/{contact}/messages/{message}": {"get": {"operationId": "message.showMessage", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve un mensaje de tu cuenta por el id que te dio el envío o un webhook. Aceptado no es entregado: el estado final llega por `message.status_changed` o por este GET. `status` es `queued`, `sent`, `delivered`, `read` o `failed` en los mensajes que enviaste. `sent`, `delivered`, `read` y `failed` tienen el mismo significado que en `message.status_changed`; `queued` es un mensaje en cola que todavía no se envió (en cola no es enviado) y no se reintenta. `status` es `null` en los mensajes recibidos, las notas y las acciones. `status` también es `null` en un mensaje enviado cuyo resultado no se conoce (el proveedor no confirmó ni rechazó el envío o el envío se interrumpió): puede haber llegado y no cambia de estado; también cuando lleva más de una hora en cola sin resultado: un mensaje cuyo envío no empezó dentro de la hora ya no sale; pasada la hora sin resultado, `status` es `null`, o `failed` con `error.reason` `not_sent` y su aviso si su envío llega tarde. Reintentar es un envío nuevo, que sólo puede duplicar si el envío había empezado y se cortó. `error` trae `code`, `title` y `reason` solo cuando `status` es `failed`. `error.reason` es `null` cuando el rechazo lo informó el proveedor; si Funnelchat decidió que un mensaje enviado con clave no salía, trae `device_unavailable`, `insufficient_balance`, `window_closed`, `recipient_unreachable`, `template_not_found`, `template_unresolved_placeholder`, `not_queued` o `not_sent`, `code` es `null` y `title` es un texto llano en el idioma de la cuenta. `client_reference` es la referencia que mandaste al enviar, o `null`. Responde 404 si el mensaje no existe o no es de ese contacto.", "summary": "GET /contacts/{contact}/messages/{message}", "tags": ["ShowMessage"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "message", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PublicMessageResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/tags": {"get": {"operationId": "tag.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /tags", "tags": ["Tag"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "withContactCount", "in": "query", "schema": {"type": "boolean"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/TagResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "tag.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /tags", "tags": ["Tag"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 254}, "description": {"type": ["string", "null"], "maxLength": 1024}, "color": {"type": ["string", "null"], "maxLength": 191}}, "required": ["name"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TagResource"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tags/{tag}": {"get": {"operationId": "tag.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /tags/{tag}", "tags": ["Tag"], "parameters": [{"name": "tag", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "withContactCount", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TagResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "tag.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /tags/{tag}", "tags": ["Tag"], "parameters": [{"name": "tag", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string"}, "description": {"type": ["string", "null"], "maxLength": 1024}, "color": {"type": ["string", "null"], "maxLength": 191}}, "required": ["name"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "examples": ["Ya existe un tag con este nombre."]}}, "required": ["message"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tags/{tag}/contacts": {"get": {"operationId": "tag.contacts", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /tags/{tag}/contacts", "tags": ["Tag"], "parameters": [{"name": "tag", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "last_message_time"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}, {"name": "sortBy", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/tags/delete": {"post": {"operationId": "tag.destroy", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /tags/delete", "tags": ["Tag"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"tagIds": {"type": "array", "items": {"type": "string"}, "minItems": 1}}, "required": ["tagIds"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tickets": {"get": {"operationId": "ticket.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /tickets", "tags": ["Ticket"], "parameters": [{"name": "status", "in": "query", "schema": {"type": "integer", "enum": ["0", "1", "2"]}}, {"name": "userId", "in": "query", "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "ticket.store", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /tickets", "tags": ["Ticket"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"userId": {"type": "integer"}, "contactId": {"type": "integer"}, "title": {"type": "string"}, "description": {"type": "string"}}, "required": ["userId", "contactId", "title", "description"]}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Ticket"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Contacto no encontrado."}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tickets/{id}": {"get": {"operationId": "ticket.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /tickets/{id}", "tags": ["Ticket"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Ticket"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "ticket.update", "description": "**Permiso requerido:** `conversations:write`", "summary": "PUT /tickets/{id}", "tags": ["Ticket"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"title": {"type": "string"}, "description": {"type": "string"}}, "required": ["title", "description"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Ticket"}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tickets/assign": {"post": {"operationId": "ticket.assignTicketToUser", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /tickets/assign", "tags": ["Ticket"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"ticketId": {"type": "integer"}, "userId": {"type": "integer"}}, "required": ["ticketId", "userId"]}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "string", "const": "Ticket successfully assigned"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tickets/{id}/close": {"post": {"operationId": "ticket.closeTicket", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /tickets/{id}/close", "tags": ["Ticket"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "string"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/tickets/{id}/reopen": {"post": {"operationId": "ticket.reOpenTicket", "description": "**Permiso requerido:** `conversations:write`", "summary": "POST /tickets/{id}/reopen", "tags": ["Ticket"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "string", "const": "Ticket re-opened"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/agents/{user}": {"get": {"operationId": "user.show", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /agents/{user}", "tags": ["User"], "parameters": [{"name": "user", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/UserResource"}, {"type": "object"}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/agents": {"get": {"operationId": "user.index", "description": "**Permiso requerido:** `conversations:read`", "summary": "GET /agents", "tags": ["User"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "email", "in": "query", "schema": {"type": "string", "format": "email"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "email", "created_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/webhooks/{webhook}/deliveries": {"get": {"operationId": "webhookDelivery.index", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve, de la más reciente a la más antigua, los intentos de entrega de una suscripción: estado, código HTTP recibido, duración y fecha del próximo reintento. Admite paginación con `perPage` (entero de 1 a 100; 25 si no se manda).", "summary": "Listar entregas de un webhook", "tags": ["WebhookDelivery"], "parameters": [{"name": "webhook", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 10000}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookDeliveryResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/webhooks/events": {"get": {"operationId": "webhookEventCatalog.index", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve el catálogo de tipos de evento a los que se puede suscribir un webhook, con su estado, si es suscribible y un ejemplo del cuerpo que se envía.", "summary": "Listar tipos de evento", "tags": ["WebhookEventCatalog"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {}}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/webhooks": {"get": {"operationId": "webhookSubscription.index", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve las suscripciones de webhook de la cuenta, de la más nueva a la más antigua. Admite paginación con `perPage` (entero de 1 a 100; 25 si no se manda).", "summary": "Listar webhooks", "tags": ["WebhookSubscription"], "parameters": [{"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 10000}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookSubscriptionResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "webhookSubscription.store", "description": "**Permiso requerido:** `conversations:write`\n\nCrea una suscripción a uno o más tipos de evento. El secreto de firma se devuelve en esta respuesta una sola vez: guardalo, no se puede volver a consultar.", "summary": "Crear un webhook", "tags": ["WebhookSubscription"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreWebhookSubscriptionRequest"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"allOf": [{"$ref": "#/components/schemas/WebhookSubscriptionResource"}, {"type": "object", "properties": {"secret": {"type": "string", "description": "Secreto de firma, en claro. Solo viene al crear la suscripción y al rotar el secreto: no se puede volver a consultar."}}, "required": ["secret"]}]}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/webhooks/{webhook}": {"get": {"operationId": "webhookSubscription.show", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve una suscripción de la cuenta por su identificador.", "summary": "Ver un webhook", "tags": ["WebhookSubscription"], "parameters": [{"name": "webhook", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookSubscriptionResource"}}, "required": ["data"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "webhookSubscription.update", "description": "**Permiso requerido:** `conversations:write`\n\nModifica la URL, los tipos de evento o el estado activo de una suscripción.", "summary": "Actualizar un webhook", "tags": ["WebhookSubscription"], "parameters": [{"name": "webhook", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateWebhookSubscriptionRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookSubscriptionResource"}}, "required": ["data"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "webhookSubscription.destroy", "description": "**Permiso requerido:** `conversations:write`\n\nElimina una suscripción. Deja de recibir eventos de inmediato.", "summary": "Eliminar un webhook", "tags": ["WebhookSubscription"], "parameters": [{"name": "webhook", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"204": {"description": "No Content"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/webhooks/{webhook}/rotate-secret": {"post": {"operationId": "webhookSubscription.rotateSecret", "description": "**Permiso requerido:** `conversations:write`\n\nGenera un secreto de firma nuevo y lo devuelve una sola vez. El anterior deja de ser válido.", "summary": "Rotar el secreto de un webhook", "tags": ["WebhookSubscription"], "parameters": [{"name": "webhook", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"allOf": [{"$ref": "#/components/schemas/WebhookSubscriptionResource"}, {"type": "object", "properties": {"secret": {"type": "string", "description": "Secreto de firma, en claro. Solo viene al crear la suscripción y al rotar el secreto: no se puede volver a consultar."}}, "required": ["secret"]}]}}, "required": ["data"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/webhooks/{webhook}/test": {"post": {"operationId": "webhook.webhookTest", "description": "**Permiso requerido:** `conversations:write`\n\nEnvía ahora un evento `webhook.test` firmado a la URL de la suscripción y devuelve el intento como un ítem del historial de entregas; queda en el historial y no se reintenta.", "summary": "Enviar un evento de prueba", "tags": ["WebhookTest"], "parameters": [{"name": "webhook", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookDeliveryResource"}}, "required": ["data"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/templates": {"get": {"operationId": "whatsappForm.templates", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve las plantillas con las que puedes empezar un formulario nuevo: `key`, `title`, `description` y `category`. El catálogo es fijo y el mismo para todas las cuentas.", "summary": "GET /forms/templates", "tags": ["WhatsappForm"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/WhatsappFormTemplate"}}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/forms": {"get": {"operationId": "whatsappForm.index", "description": "**Permiso requerido:** `conversations:read`\n\nLista los formularios de tu cuenta, uno por formulario aunque tenga varias versiones; de cada uno ves la versión que usas hoy (la publicada o, si no hay, la más nueva). El `id` de cada fila es el de esa versión y `family_id` es el del formulario. Filtra con `q` (parte del nombre), `status` (`draft`, `published` o `deprecated`) y `device_id` (un número de tu cuenta; si no es WhatsApp Cloud responde 422 `NUMBER_NOT_ELIGIBLE`). Pagina con `perPage` (1 a 100, 25 por defecto).", "summary": "GET /forms", "tags": ["WhatsappForm"], "parameters": [{"name": "q", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 191}}, {"name": "status", "in": "query", "schema": {"type": ["string", "null"], "enum": ["draft", "published", "deprecated", null]}}, {"name": "device_id", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "page", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/WhatsappFormResource"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "whatsappForm.store", "description": "**Permiso requerido:** `conversations:write`\n\nCrea un formulario nuevo como borrador de tu cuenta. Envía `template_key` (una de las `key` de `GET /forms/templates`; `blank` empieza vacío), `device_id` (un número de WhatsApp Cloud de tu cuenta) y, si quieres, `device_ids` con otros números donde también vivirá. Responde 201 con la versión (`id`), su `family_id`, `lint` y `numbers`. Si un número no es de tu cuenta o no es WhatsApp Cloud responde 422 `NUMBER_NOT_ELIGIBLE`.", "summary": "POST /forms", "tags": ["WhatsappForm"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreWhatsappFormRequest"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WhatsappFormResource"}, "lint": {"type": "array", "items": {}}, "numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["data", "lint", "numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/families/{familyId}/metrics": {"get": {"operationId": "whatsappForm.metrics", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve los números de un formulario de tu cuenta: cuántos se enviaron, cuántos se abrieron y cuántos se completaron, y sus porcentajes. `{familyId}` es el `family_id` del formulario. Acepta los mismos filtros de fecha, versión y origen que la lista de respuestas; un filtro inválido responde 422. Responde 404 si el formulario no existe o no es de tu cuenta.", "summary": "GET /forms/families/{familyId}/metrics", "tags": ["WhatsappForm"], "parameters": [{"name": "familyId", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "from", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "to", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "version_id", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "origin", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "status", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "kind", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "effect_status", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "search", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 191}}, {"name": "per_page", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "page", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "object", "properties": {"not_sent": {"type": "integer"}, "not_sent_reasons": {"type": "array", "items": {"anyOf": [{"type": "object", "properties": {"reason": {"type": "string"}, "label": {"type": "string"}, "count": {"type": "integer"}}, "required": ["reason", "label", "count"]}, {"type": "object", "properties": {"reason": {"type": "string", "const": "desconocido"}, "label": {"type": "string", "const": "sin motivo registrado"}, "count": {"type": "integer"}}, "required": ["reason", "label", "count"]}]}}, "sent": {"type": "integer"}, "delivered": {"type": "integer"}, "read": {"type": "integer"}, "completed": {"type": "integer"}, "pending": {"type": "integer"}, "unfinished": {"type": "integer"}, "partial": {"type": "integer"}, "completion_rate": {"type": ["number", "null"]}, "delivery_rate": {"type": ["number", "null"]}, "read_rate": {"type": ["number", "null"]}, "median_seconds_to_complete": {"type": ["integer", "null"]}}, "required": ["not_sent", "not_sent_reasons", "sent", "delivered", "read", "completed", "pending", "unfinished", "partial", "completion_rate", "delivery_rate", "read_rate", "median_seconds_to_complete"]}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/forms/families/{familyId}/responses": {"get": {"operationId": "whatsappForm.responses", "description": "**Permiso requerido:** `conversations:read`\n\nLista las respuestas de un formulario de tu cuenta, de la más reciente a la más antigua, sumando todas sus versiones. Junto a `data` viene `columns`, las preguntas que usan esas respuestas. `{familyId}` es el `family_id` del formulario. Filtra con `from` y `to` (fechas), `version_id` (el `id` de una versión de ese formulario), `origin`, `status` y `search` (nombre o teléfono del contacto). Un filtro con un valor inválido responde 422. Pagina con `perPage` (1 a 100, 25 por defecto). Responde 404 si el formulario no existe o no es de tu cuenta.", "summary": "GET /forms/families/{familyId}/responses", "tags": ["WhatsappForm"], "parameters": [{"name": "familyId", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "from", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "to", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "version_id", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "origin", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "status", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "kind", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "effect_status", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 24}}, {"name": "search", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 191}}, {"name": "page", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object"}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:read"}}, "/forms/families/{familyId}/responses/{runId}": {"get": {"operationId": "whatsappForm.response", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve una respuesta completa de un formulario de tu cuenta: las respuestas del contacto y lo que se hizo con ellas. `{familyId}` es el `family_id` del formulario y `{runId}` el `id` de la respuesta que viene en `GET /forms/families/{familyId}/responses`. Responde 404 si no existe o no es de tu cuenta.", "summary": "GET /forms/families/{familyId}/responses/{runId}", "tags": ["WhatsappForm"], "parameters": [{"name": "familyId", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "runId", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "object", "properties": {"id": {"type": "integer"}, "flow_token": {"type": "string"}, "contact": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": ["string", "null"]}, "phone": {"type": ["string", "null"]}}, "required": ["id", "name", "phone"]}, "status": {"anyOf": [{"type": "object", "properties": {"key": {"type": "string", "const": "completed"}, "label": {"type": "string", "const": "Completado"}}, "required": ["key", "label"]}, {"type": "object", "properties": {"key": {"type": "string", "const": "pending"}, "label": {"type": "string", "const": "Esperando respuesta"}}, "required": ["key", "label"]}, {"type": "object", "properties": {"key": {"type": "string", "const": "unfinished"}, "label": {"type": "string", "const": "Sin completar"}}, "required": ["key", "label"]}, {"type": "object", "properties": {"key": {"type": "string", "const": "not_sent"}, "label": {"type": "string", "const": "No enviado"}}, "required": ["key", "label"]}]}, "origin": {"type": "string"}, "node_id": {"type": ["string", "null"]}, "automation_run_id": {"type": ["integer", "null"]}, "conversation_id": {"type": ["integer", "null"]}, "version": {"type": "integer"}, "version_id": {"type": "integer"}, "output_id": {"type": ["string", "null"]}, "output_label": {"type": ["string", "null"]}, "reason": {"type": ["string", "null"]}, "reason_label": {"type": ["string", "null"]}, "completed_after_expiry": {"type": "boolean"}, "partial": {"type": "string"}, "last_screen_id": {"type": ["string", "null"]}, "sent_at": {"type": ["string", "null"]}, "delivered_at": {"type": ["string", "null"]}, "read_at": {"type": ["string", "null"]}, "responded_at": {"type": ["string", "null"]}, "expires_at": {"type": ["string", "null"]}, "answers": {"type": "array", "items": {"type": "object", "properties": {"name": {"type": "string"}, "label": {"type": "string"}, "value": {"type": "string"}, "unknown": {"type": "boolean"}}, "required": ["name", "label", "value", "unknown"]}}, "effects": {"type": "array", "items": {"anyOf": [{"type": "array"}, {"type": "object", "properties": {"id": {"type": "integer"}, "run_id": {"type": "integer"}, "kind": {"type": "string"}, "kind_label": {"type": "string"}, "status": {"type": "string"}, "attempts": {"type": "integer"}, "max_attempts": {"type": "integer"}, "next_attempt_at": {"type": ["string", "null"]}, "payload": {"type": "array", "items": {}}, "request_excerpt": {"type": ["string", "null"]}, "response_excerpt": {"type": ["string", "null"]}, "created_at": {"type": ["string", "null"]}}, "required": ["id", "run_id", "kind", "kind_label", "status", "attempts", "max_attempts", "next_attempt_at", "payload", "request_excerpt", "response_excerpt", "created_at"]}]}}, "response_json": {"type": ["array", "null"], "items": {}}}, "required": ["id", "flow_token", "contact", "status", "origin", "node_id", "automation_run_id", "conversation_id", "version", "version_id", "output_id", "output_label", "reason", "reason_label", "completed_after_expiry", "partial", "last_screen_id", "sent_at", "delivered_at", "read_at", "responded_at", "expires_at", "answers", "effects", "response_json"]}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/forms/families/{familyId}/versions": {"get": {"operationId": "whatsappForm.versions", "description": "**Permiso requerido:** `conversations:read`\n\nLista las versiones de un formulario de tu cuenta, de la más nueva a la más vieja, con su estado, si es la vigente y cuántas respuestas recibió cada una. `{familyId}` es el `family_id` del formulario. Pagina con `perPage` (1 a 100, 25 por defecto). Responde 404 si el formulario no existe o no es de tu cuenta.", "summary": "GET /forms/families/{familyId}/versions", "tags": ["WhatsappForm"], "parameters": [{"name": "familyId", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "default": 25, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "integer"}, "version": {"type": "integer"}, "name": {"type": "string"}, "status": {"type": "string"}, "is_current": {"type": "boolean"}, "published_at": {"type": ["string", "null"]}, "deprecated_at": {"type": ["string", "null"]}, "meta_flow_id": {"type": ["string", "null"]}, "retained_reason": {"type": ["string", "null"]}, "responses": {"type": "integer"}, "templates": {"type": "integer"}}, "required": ["id", "version", "name", "status", "is_current", "published_at", "deprecated_at", "meta_flow_id", "retained_reason", "responses", "templates"]}}, "links": {"type": "object", "properties": {"first": {"type": ["string", "null"]}, "last": {"type": ["string", "null"]}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/forms/families/{familyId}/definition": {"get": {"operationId": "whatsappForm.definition", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve la definición de un formulario: la de la versión publicada o, si todavía no hay ninguna, la de la versión más nueva. `{familyId}` es el `family_id` del formulario, no el `id` de una versión. Responde 404 si el formulario no existe o no es de tu cuenta.", "summary": "GET /forms/families/{familyId}/definition", "tags": ["WhatsappForm"], "parameters": [{"name": "familyId", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"data": {"type": "object", "properties": {"family_id": {"type": "integer"}, "form_id": {"type": "integer"}, "name": {"type": "string"}, "status": {"type": "string"}, "version": {"type": "integer"}, "definition": {"anyOf": [{"type": "array"}, {"type": "object", "properties": {"screens": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}}, "required": ["screens"]}]}}, "required": ["family_id", "form_id", "name", "status", "version", "definition"]}}, "required": ["data"]}, {"type": "object", "properties": {"data": {"type": "null"}}, "required": ["data"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}}, "/forms/{id}": {"get": {"operationId": "whatsappForm.show", "description": "**Permiso requerido:** `conversations:read`\n\nDevuelve una versión de un formulario de tu cuenta con su definición y su detalle. `{id}` es el `id` de la versión (el de las filas de `GET /forms`), no el `family_id`. Trae además `lint` (lo que falta corregir antes de publicar), `versions` (las versiones del formulario) y `numbers` (los números donde vive). Responde 404 si la versión no existe o no es de tu cuenta.", "summary": "GET /forms/{id}", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WhatsappFormResource"}, "lint": {"type": "array", "items": {}}, "versions": {"type": "array", "items": {"$ref": "#/components/schemas/WhatsappForm"}}, "numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["data", "lint", "versions", "numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "put": {"operationId": "whatsappForm.update", "description": "**Permiso requerido:** `conversations:write`\n\nGuarda la definición de un borrador. `{id}` es el `id` de la versión. Envía `definition` con `screens` (cada pantalla con `id` de texto y `items`; cada bloque con `type`, y las preguntas con `name`) y, si quieres, `name` y `expected_updated_at`. Una definición con la forma rota responde 422 con el error en su ruta. Lo incompleto (sin título, sin bloques, etiquetas vacías) se guarda y la respuesta trae en `lint` lo que falta corregir. Responde 409 `PUBLISHED` si la versión ya está publicada (crea otra con `POST /forms/{id}/versions`) y 409 `STALE` si `expected_updated_at` no es el último guardado. Responde 404 si no existe o no es de tu cuenta.", "summary": "PUT /forms/{id}", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SaveWhatsappFormRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WhatsappFormResource"}, "lint": {"type": "array", "items": {}}}, "required": ["data", "lint"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}, "delete": {"operationId": "whatsappForm.destroy", "description": "**Permiso requerido:** `conversations:write`\n\nElimina un borrador. `{id}` es el `id` de la versión. Un formulario publicado no se elimina: responde 409 `PUBLISHED`. Responde 404 si la versión no existe o no es de tu cuenta.", "summary": "DELETE /forms/{id}", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"204": {"description": "No Content", "content": {"application/json": {"schema": {"type": "array", "items": {}}}}}, "409": {"description": "Conflict", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "const": "PUBLISHED"}, "message": {"type": "string", "const": "Un formulario publicado no se elimina; se depreca."}}, "required": ["error", "message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/{id}/numbers": {"get": {"operationId": "whatsappForm.numbersIndex", "description": "**Permiso requerido:** `conversations:read`\n\nLista los números de WhatsApp Cloud donde vive una versión de formulario de tu cuenta y el estado de cada uno (`draft`, `publishing`, `published` o `failed`). El primero es el número con el que se creó. `{id}` es el `id` de la versión. Responde 404 si la versión no existe o no es de tu cuenta.", "summary": "GET /forms/{id}/numbers", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:read"}, "post": {"operationId": "whatsappForm.addNumber", "description": "**Permiso requerido:** `conversations:write`\n\nSuma un número de WhatsApp Cloud a una versión de formulario. `{id}` es el `id` de la versión y `device_id` el número de tu cuenta. Si la versión ya está publicada, se publica en ese número de inmediato. Responde `numbers` con el estado de cada número; si el número no es de tu cuenta o no es WhatsApp Cloud responde 422 `NUMBER_NOT_ELIGIBLE`. Puedes llamarla hasta 30 veces por minuto.", "summary": "POST /forms/{id}/numbers", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AddFormNumberRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/{id}/versions": {"post": {"operationId": "whatsappForm.storeVersion", "description": "**Permiso requerido:** `conversations:write`\n\nCrea la versión siguiente de un formulario publicado, como borrador, para poder cambiarlo. `{id}` es el `id` de la versión desde la que partes. Responde 201 con la versión nueva, o 200 con `created: false` si el formulario ya tenía un borrador (ese borrador es la respuesta). Responde 404 si la versión no existe o no es de tu cuenta.", "summary": "POST /forms/{id}/versions", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "string"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/{id}/sync": {"post": {"operationId": "whatsappForm.sync", "description": "**Permiso requerido:** `conversations:write`\n\nValida una versión en Meta sin publicarla. `{id}` es el `id` de la versión. Responde la versión con `lint` y lo que Meta observó. Si Meta rechaza la llamada responde 502 `META`. Responde 404 si no existe o no es de tu cuenta. Puedes llamarla hasta 30 veces por minuto.", "summary": "POST /forms/{id}/sync", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WhatsappFormResource"}, "lint": {"type": "array", "items": {}}, "numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["data", "lint", "numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/{id}/publish": {"post": {"operationId": "whatsappForm.publish", "description": "**Permiso requerido:** `conversations:write`\n\nPublica una versión en Meta; la publicación es inmediata. `{id}` es el `id` de la versión. Si la definición tiene errores responde 422 `LINT` con la lista; si Meta rechaza la llamada, 502 `META`. Los otros números del formulario se publican en segundo plano: consulta su estado en `GET /forms/{id}/numbers`. Responde 404 si no existe o no es de tu cuenta. Puedes llamarla hasta 30 veces por minuto.", "summary": "POST /forms/{id}/publish", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WhatsappFormResource"}, "lint": {"type": "array", "items": {}}, "numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["data", "lint", "numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/{id}/numbers/{deviceId}": {"delete": {"operationId": "whatsappForm.removeNumber", "description": "**Permiso requerido:** `conversations:write`\n\nQuita un número de una versión de formulario: deja de enviarse por él. `{id}` es el `id` de la versión y `{deviceId}` el número de tu cuenta. El número con el que se creó el formulario no se quita: responde 422 `PRIMARY_NUMBER`. Responde 404 si la versión o el número no existen o no son de tu cuenta.", "summary": "DELETE /forms/{id}/numbers/{deviceId}", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "deviceId", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["numbers"]}}}}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "const": "PRIMARY_NUMBER"}, "message": {"type": "string", "const": "El número con el que se creó el formulario no se puede quitar."}}, "required": ["error", "message"]}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "examples": [""]}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/forms/{id}/numbers/retry": {"post": {"operationId": "whatsappForm.retryNumbers", "description": "**Permiso requerido:** `conversations:write`\n\nReintenta publicar los números que fallaron o que aún no se publicaron en una versión ya publicada. `{id}` es el `id` de la versión. Responde `numbers` con el estado de cada número. Responde 404 si no existe o no es de tu cuenta.", "summary": "POST /forms/{id}/numbers/retry", "tags": ["WhatsappForm"], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"numbers": {"type": "array", "prefixItems": [{"type": "object", "properties": {"device_id": {}, "primary": {"type": "boolean"}, "status": {"type": "string"}, "error": {"type": "string"}}, "required": ["device_id", "primary", "status", "error"]}], "minItems": 1, "maxItems": 1}}, "required": ["numbers"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}, "x-fc-permission": "conversations:write"}}, "/contacts/{contact}/message/form": {"post": {"operationId": "whatsappFormSend.store", "description": "**Permiso requerido:** `conversations:send`\n\nEnvía a un contacto un formulario de WhatsApp publicado. `form_id` es el identificador estable del formulario (el mismo en todas sus versiones) y `device_id` el número de WhatsApp Cloud de tu cuenta por el que sale. `text` (hasta 1024 caracteres) acompaña al formulario y por defecto es su nombre; `button_text` (hasta 30 caracteres, sin emojis) es el botón y por defecto es «Abrir» u «Open» según el idioma del usuario de la clave (en inglés «Open»; en español y portugués «Abrir»). Sólo funciona dentro de las 24 horas siguientes al último mensaje del contacto a ese número. Responde `200` con el mensaje en cola (`status` `queued`, `type` `whatsapp_form`); aceptado no es entregado: el estado final llega por `message.status_changed` o por `GET /contacts/{contact}/messages/{message}`, y la respuesta del contacto por `whatsapp_form.completed`. Responde `404` si el contacto no existe o no es de tu cuenta, o `404` con `form_not_found` si el formulario no existe en tu cuenta. Responde `422` con `device_unavailable` si el número no es de tu cuenta o no está conectado, `number_not_eligible` si no es un número de WhatsApp Cloud que pueda enviar formularios, `form_not_published` si el formulario no tiene versión publicada, `form_not_on_number` si no está publicado en ese número, `recipient_unreachable` si el contacto no tiene teléfono ni identificador de WhatsApp y `window_closed` si pasaron más de 24 horas. También responde `422` por las guardas de envío y `429` con `rate_limited` si superas el ritmo del número o del contacto.\n\nSi tu cuenta está bloqueada por el límite de contactos activos, responde `429` con `mac_lockout_24h` (además del `429` `rate_limited` del ritmo) y no guarda ningún mensaje ni `client_reference`. Si Funnelchat no pudo poner el mensaje en cola, la respuesta no es un error: es `200` con el mensaje en estado `failed` y `error.reason` `not_queued`; no salió, así que reintentar no lo duplica.", "summary": "POST /contacts/{contact}/message/form", "tags": ["WhatsappFormSend"], "parameters": [{"name": "contact", "in": "path", "required": true, "schema": {"type": "integer"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SendWhatsappFormRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"anyOf": [{"$ref": "#/components/schemas/PublicMessageResource"}, {"type": "null"}]}}, "required": ["message"]}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"error": {"type": "string", "enum": ["form_not_found"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["window_closed", "antiblock_duplicate_content", "antiblock_unanswered_limit", "recipient_unsupported"]}, "message": {"type": "string"}}, "required": ["error", "message"]}, {"type": "object", "properties": {"error": {"type": "string", "enum": ["device_unavailable", "not_sent", "number_not_eligible", "form_not_published", "form_not_on_number", "recipient_unreachable", "window_closed"]}, "message": {"type": "string"}}, "required": ["error", "message"]}]}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "enum": ["rate_limited"]}, "message": {"type": "string"}}, "required": ["error", "message"]}}}, "headers": {"Retry-After": {"required": true, "schema": {"type": "integer"}}}}, "500": {"description": "Internal Server Error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "enum": ["Server Error"]}}, "required": ["message"]}}}}}, "x-fc-permission": "conversations:send"}}}, "components": {"securitySchemes": {"http": {"type": "http", "scheme": "bearer"}}, "schemas": {"AddFormNumberRequest": {"type": "object", "properties": {"device_id": {"type": "integer", "minimum": 1}}, "required": ["device_id"], "title": "AddFormNumberRequest"}, "BroadcastContactResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "phone": {"type": "string"}, "whatsapp_id": {"type": "string"}, "email": {"type": "string"}, "image": {"type": "string"}}, "required": ["id", "name", "phone", "whatsapp_id", "email", "image"], "title": "BroadcastContactResource"}, "BroadcastCostResource": {"type": "object", "properties": {"broadcast_id": {"type": "string"}, "currency": {"type": "string", "const": "USD"}, "is_partial": {"type": "boolean"}, "estimate": {"type": ["object", "null"], "properties": {"category": {"type": ["string", "null"]}, "currency": {"type": "string"}, "contacts": {"type": "integer"}, "unpriced_contacts": {"type": "integer"}, "total": {"type": "number"}, "per_market": {"type": "array", "items": {"type": "object", "properties": {"market": {"type": "string"}, "contacts": {"type": "integer"}, "rate": {"type": ["number", "null"]}, "cost": {"type": "number"}}, "required": ["market", "contacts", "rate", "cost"]}}, "rates_updated_at": {"type": ["string", "null"]}, "computed_at": {"type": ["string", "null"]}}, "required": ["category", "currency", "contacts", "unpriced_contacts", "total", "per_market", "rates_updated_at", "computed_at"]}, "computed": {"type": "object", "properties": {"total": {"type": "number"}, "sent": {"type": "integer", "const": 0}, "billed": {"type": "integer", "const": 0}, "free": {"type": "integer", "const": 0}, "pending_price": {"type": "integer", "const": 0}, "no_data": {"type": "integer", "const": 0}, "category": {"type": ["null", "string", "integer", "object"]}, "per_market": {"type": "array", "items": {"type": "object", "properties": {"market": {"type": "string"}, "contacts": {"type": "integer"}, "rate": {"type": ["number", "null"]}, "cost": {"type": "number"}}, "required": ["market", "contacts", "rate", "cost"]}}}, "required": ["total", "sent", "billed", "free", "pending_price", "no_data", "category", "per_market"]}, "rates_updated_at": {"type": ["string", "null"]}}, "required": ["broadcast_id", "currency", "is_partial", "estimate", "computed", "rates_updated_at"], "title": "BroadcastCostResource"}, "BroadcastCostTiersResource": {"type": "object", "properties": {"tiers": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "rates_updated_at": {"type": ["string", "null"]}}, "required": ["tiers", "rates_updated_at"], "title": "BroadcastCostTiersResource"}, "BroadcastFolderResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "broadcasts_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}}, "required": ["id", "name", "broadcasts_count"], "title": "BroadcastFolderResource"}, "BroadcastMessageResource": {"type": "object", "properties": {"contact_id": {"type": "string"}, "contact_name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "contact_phone": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "contact_image": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "message_status": {"type": ["string", "null"]}, "message_info": {"type": "object", "properties": {"message": {"anyOf": [{"type": "string"}, {}]}, "error_code": {"anyOf": [{"type": "string"}, {}]}, "error": {"anyOf": [{"type": "string"}, {}]}, "error_category": {"anyOf": [{"type": ["string", "null"]}, {}]}}, "required": ["message", "error_code", "error", "error_category"], "additionalProperties": {}}, "skip_reason": {"type": ["string", "null"]}, "skipped_at": {"type": ["string", "null"]}, "recipient_state": {"type": "string"}, "sent_at": {"type": ["string", "null"]}}, "required": ["contact_id", "contact_name", "contact_phone", "contact_image", "message_status", "message_info", "skip_reason", "skipped_at", "recipient_state", "sent_at"], "title": "BroadcastMessageResource"}, "BroadcastResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "device_id": {"type": ["integer", "null"]}, "template_id": {"anyOf": [{"type": "integer"}, {"type": "string", "enum": [""]}]}, "template": {"type": ["string", "null"]}, "folder": {"type": ["object", "null"], "properties": {"id": {"type": "integer"}, "name": {"type": "string"}}, "required": ["id", "name"]}, "value": {"type": ["array", "null"], "items": {}}, "template_button_flows": {"type": ["array", "null"], "items": {}}, "included_tags": {"type": "array", "items": {"$ref": "#/components/schemas/TagResource"}}, "excluded_tags": {"type": "array", "items": {"$ref": "#/components/schemas/TagResource"}}, "some_tags": {"type": "array", "items": {"$ref": "#/components/schemas/TagResource"}}, "countries": {"type": ["array", "null"], "items": {}}, "kanban_setting_id": {"type": ["integer", "null"]}, "kanban_stage_ids": {"type": ["array", "null"], "items": {}}, "only_stagnant": {"type": "boolean"}, "lead_score_categories": {"type": ["array", "null"], "items": {}}, "lead_score_min": {"type": ["integer", "null"]}, "lead_score_max": {"type": ["integer", "null"]}, "exclude_never_replied": {"type": "boolean"}, "date_from": {"type": "string"}, "date_to": {"type": "string"}, "send_at": {"type": "string"}, "contacts_count": {"type": ["string", "integer", "null"]}, "delivered_messages_count": {"type": "null"}, "readed_messages_count": {"type": "null"}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}, "status": {"$ref": "#/components/schemas/BroadcastStatusEnum"}, "shipping_speed": {"$ref": "#/components/schemas/BroadcastShippingSpeedEnum"}, "risk_acceptance": {"type": ["object", "null"], "properties": {"accepted_by_name": {"type": ["string", "null"]}, "accepted_at": {"type": "string"}, "audience_count": {"type": ["integer", "null"]}, "provider": {"type": ["string", "null"]}, "risk_codes": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}}, "required": ["accepted_by_name", "accepted_at", "audience_count", "provider", "risk_codes"]}, "missing_data_audit": {"type": ["object", "null"], "properties": {"audience_count": {"type": "integer"}, "affected_count": {"type": "integer"}, "items": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "unknown_custom_fields": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}}, "required": ["audience_count", "affected_count", "items", "unknown_custom_fields"]}, "smart_send": {"type": "boolean"}, "smart_send_state": {"type": ["object", "null"], "properties": {"batch_size": {"type": "string"}, "pages_per_batch": {"type": "string"}, "current_batch": {"type": "string"}, "total_batches": {"type": "string"}, "quality": {"type": "string"}, "quality_baseline": {"type": "string"}, "checked_at": {"type": "string"}, "resume_page": {"type": "string"}, "page_size": {"type": "string"}, "total_pages": {"type": "string"}, "paused_at": {"type": "string"}, "pause_reason": {"type": "string"}, "quality_read_failures": {"type": "string"}, "cancelled_at": {"type": "string"}}, "required": ["batch_size", "pages_per_batch", "current_batch", "total_batches", "quality", "quality_baseline", "checked_at", "resume_page", "page_size", "total_pages", "paused_at", "pause_reason", "quality_read_failures", "cancelled_at"]}, "failure_reason": {"type": ["object", "null"], "properties": {"reason": {"type": ["string", "null"]}}, "required": ["reason"]}, "send_mode": {"$ref": "#/components/schemas/BroadcastSendModeEnum"}, "protect_template_category": {"type": "boolean"}}, "required": ["id", "name", "device_id", "template_id", "template", "folder", "value", "template_button_flows", "included_tags", "excluded_tags", "some_tags", "countries", "kanban_setting_id", "kanban_stage_ids", "only_stagnant", "lead_score_categories", "lead_score_min", "lead_score_max", "exclude_never_replied", "date_from", "date_to", "send_at", "contacts_count", "delivered_messages_count", "readed_messages_count", "created_at", "updated_at", "status", "shipping_speed", "risk_acceptance", "missing_data_audit", "smart_send", "smart_send_state", "failure_reason", "send_mode", "protect_template_category"], "title": "BroadcastResource"}, "BroadcastSendModeEnum": {"type": "string", "enum": ["now", "schedule", "after_approval"], "title": "BroadcastSendModeEnum"}, "BroadcastShippingSpeedEnum": {"type": "integer", "enum": [0, 1, 2], "title": "BroadcastShippingSpeedEnum"}, "BroadcastStatusEnum": {"type": "integer", "enum": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], "title": "BroadcastStatusEnum"}, "BroadcastsResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "device_id": {"type": "string"}, "template_id": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "folder_id": {"type": "string"}, "value": {"type": "string"}, "date_from": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "date_to": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "send_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "contacts_count": {"type": "string"}, "created_at": {"type": "string"}, "updated_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "status": {"type": "string"}, "shipping_speed": {"type": "string"}, "delivered_messages_count": {"type": ["string", "null"]}, "readed_messages_count": {"type": ["string", "null"]}, "replied_messages_count": {"type": ["string", "null"]}, "failure_reason": {"type": ["object", "null"], "properties": {"reason": {"type": ["string", "null"]}}, "required": ["reason"]}, "send_mode": {"type": "string"}, "protect_template_category": {"type": "boolean"}}, "required": ["id", "name", "device_id", "template_id", "folder_id", "value", "date_from", "date_to", "send_at", "contacts_count", "created_at", "updated_at", "status", "shipping_speed", "delivered_messages_count", "readed_messages_count", "replied_messages_count", "failure_reason", "send_mode", "protect_template_category"], "title": "BroadcastsResource"}, "BulkMoveStageRequest": {"type": "object", "properties": {"contact_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1, "maxItems": 200}, "stage_id": {"type": "integer"}}, "required": ["contact_ids", "stage_id"], "title": "BulkMoveStageRequest"}, "BulkRemoveStageRequest": {"type": "object", "properties": {"contact_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1, "maxItems": 200}}, "required": ["contact_ids"], "title": "BulkRemoveStageRequest"}, "ContactCustomFieldResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "description": {"type": "string"}, "type": {"type": "string"}, "value": {"type": "string"}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}, "contact_count": {"type": "string"}}, "required": ["id", "name", "description", "type", "value", "created_at", "updated_at", "contact_count"], "title": "ContactCustomFieldResource"}, "ContactFlowListResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "running": {"type": "boolean"}, "created_at": {"type": ["string", "null"]}, "last_run_at": {"type": ["string", "null"]}}, "required": ["id", "name", "running", "created_at", "last_run_at"], "title": "ContactFlowListResource"}, "ContactKanbanStageBoardResource": {"type": "object", "properties": {"kanban_setting_id": {"type": "string"}, "kanban_name": {"type": "string"}, "current_stage_id": {"type": "string"}, "value_custom_field_id": {"type": "string"}, "profit_custom_field_id": {"type": "string"}, "stages": {"type": "string"}}, "required": ["kanban_setting_id", "kanban_name", "current_stage_id", "value_custom_field_id", "profit_custom_field_id", "stages"], "title": "ContactKanbanStageBoardResource"}, "ContactLeadScoreResource": {"type": "object", "properties": {"score": {"type": "string"}, "signals_count": {"type": "string"}, "category": {"type": "string"}, "confidence": {"type": "string"}, "disqualified": {"type": "string"}, "disqualified_at": {"type": "string"}, "disqualification_reasons": {"type": "string"}, "updated_at": {"type": ["string", "null"]}, "events": {"type": "array", "items": {"$ref": "#/components/schemas/LeadScoreEventResource"}}, "next_cursor": {"type": "string"}, "has_more": {"type": "boolean"}}, "required": ["score", "signals_count", "category", "confidence", "disqualified", "disqualified_at", "disqualification_reasons", "updated_at", "events", "next_cursor", "has_more"], "title": "ContactLeadScoreResource"}, "ContactNoteResource": {"type": "object", "properties": {"id": {"type": "integer"}, "contact_id": {"type": "integer"}, "author_id": {"type": ["integer", "null"]}, "author_name": {}, "body": {"type": "string"}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}}, "required": ["id", "contact_id", "author_id", "author_name", "body", "created_at", "updated_at"], "title": "ContactNoteResource"}, "ContactResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "email": {"type": "string"}, "phone": {"type": "string"}, "whatsapp_id": {"type": "string"}, "whatsapp_username": {"type": ["string", "null"]}, "has_phone": {"type": "boolean"}, "country_code": {"type": "string"}, "status": {"type": "integer"}, "image": {"type": "string"}, "notes": {"type": ["string", "null"], "deprecated": true}, "custom_fields": {"type": "array", "items": {"$ref": "#/components/schemas/ContactCustomFieldResource"}}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "active_conversation": {"type": "integer"}, "favorite": {"type": "integer"}, "unread_messages": {"type": "integer"}, "manually_unread": {"type": "boolean"}, "last_message": {"type": "object", "properties": {"text": {"type": "string"}, "file": {"type": "string"}, "date": {"type": "string"}, "type": {"type": "string"}, "own": {"type": "string"}, "deleted_at": {"type": "string"}, "deleted_scope": {"type": "string"}}, "required": ["text", "file", "date", "type", "own", "deleted_at", "deleted_scope"]}, "device_id": {"type": ["integer", "null"]}, "adviser_id": {"type": ["integer", "null"]}, "paused_at": {"type": ["string", "null"]}, "mac_date": {"type": ["string", "null"]}, "is_mac_inactive": {"type": "boolean", "description": "`true` si el contacto es inactivo por el límite de contactos activos en el momento de la consulta: tu cuenta está en bloqueo (`state` = `enforcing` en `GET /mac/status`) y el contacto todavía no es un contacto activo del ciclo actual. Viene en `GET /contacts`, `GET /contacts/{contact}` y `GET /conversations`."}, "ai_assistant_name": {"type": ["string", "null"]}, "stage_since": {"type": "string"}, "is_stagnant": {"type": "boolean"}, "lead_score": {"type": "object", "properties": {"score": {"type": "integer"}, "signals_count": {"type": "integer"}, "category": {"type": "string"}, "confidence": {"type": "string"}, "disqualified": {"type": "boolean"}, "disqualified_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}}, "required": ["score", "signals_count", "category", "confidence", "disqualified", "disqualified_at", "updated_at"]}, "name_mismatch": {"type": ["array", "null"], "items": {}}}, "required": ["id", "name", "email", "phone", "whatsapp_id", "has_phone", "country_code", "status", "image", "notes", "created_at", "active_conversation", "favorite", "unread_messages", "device_id", "adviser_id", "paused_at", "mac_date", "ai_assistant_name"], "title": "ContactResource"}, "ContactTagResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "description": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "color": {"type": "string"}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}, "contact_count": {"type": "string"}, "assigned_at": {"type": ["string", "null"]}, "last_updated": {"type": ["string", "null"]}}, "required": ["id", "name", "description", "color", "created_at", "updated_at", "contact_count", "assigned_at", "last_updated"], "title": "ContactTagResource"}, "CursorPaginator": {"type": "object", "properties": {"data": {"type": "string"}, "path": {"type": ["string", "null"]}, "per_page": {"type": "integer"}, "next_cursor": {"type": ["string", "null"]}, "next_page_url": {"type": ["string", "null"]}, "prev_cursor": {"type": ["string", "null"]}, "prev_page_url": {"type": ["string", "null"]}}, "required": ["data", "path", "per_page", "next_cursor", "next_page_url", "prev_cursor", "prev_page_url"], "title": "CursorPaginator"}, "CustomFieldResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "type": {"$ref": "#/components/schemas/CustomFieldTypeEnum"}, "description": {"type": ["string", "null"]}, "contact_count": {"type": "integer"}, "created_at": {"type": ["string", "null"], "format": "date-time"}}, "required": ["id", "name", "type", "description", "created_at"], "title": "CustomFieldResource"}, "CustomFieldTypeEnum": {"type": "integer", "enum": [0, 1, 2, 3, 4], "title": "CustomFieldTypeEnum"}, "FlowResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "uuid": {"type": "string"}, "first_node_uuid": {"type": "string"}, "enable": {"type": "string"}, "valid": {"type": "string"}, "executions": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "created_at": {"type": "string"}, "updated_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "nodes_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "trigger_uuid": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "trigger_device_ids": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "trigger_type": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "trigger_values": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "trigger_is_global": {"type": "boolean"}, "trigger_save_activation_phrase": {"type": "boolean"}, "trigger_activation_phrase_field_id": {"type": ["string", "null"]}, "payment_platform": {"type": ["string", "null"]}, "payment_external_product_id": {"type": ["string", "null"]}, "payment_event_types": {"type": ["string", "null"]}, "payment_event_entry_nodes": {"type": ["string", "null"]}, "default": {"type": "string"}, "once_per_contact": {"type": "string"}, "frequency_limit_value": {"type": "string"}, "frequency_limit_unit": {"type": ["string", "null"]}, "frequency_limit_minutes": {"type": "string"}, "folder": {"$ref": "#/components/schemas/FolderResource"}, "nodes": {"type": "array", "items": {"$ref": "#/components/schemas/NodeResource"}}, "inbound_origins": {"type": "string"}, "intention_prompt": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "match_location": {"type": ["string", "null"]}, "match_details": {"type": ["string", "null"]}, "risk_acceptance": {"type": ["object", "null"], "properties": {"accepted_by_name": {"type": ["string", "null"]}, "accepted_at": {"type": "string"}, "codes": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}}, "required": ["accepted_by_name", "accepted_at", "codes"]}}, "required": ["id", "name", "uuid", "first_node_uuid", "enable", "valid", "executions", "created_at", "updated_at", "nodes_count", "trigger_device_ids", "trigger_type", "trigger_is_global", "trigger_save_activation_phrase", "trigger_activation_phrase_field_id", "payment_platform", "payment_external_product_id", "payment_event_types", "payment_event_entry_nodes", "default", "once_per_contact", "frequency_limit_value", "frequency_limit_unit", "frequency_limit_minutes", "intention_prompt", "match_location", "match_details", "risk_acceptance"], "title": "FlowResource"}, "FolderResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "parent_id": {"type": "string"}, "children": {"type": "array", "items": {"$ref": "#/components/schemas/FolderResource"}}, "flows_count": {"type": "integer"}}, "required": ["id", "name", "parent_id"], "title": "FolderResource"}, "ForwardMessageRequest": {"type": "object", "properties": {"targets": {"type": "array", "items": {"type": "object", "properties": {"contact_id": {"type": "integer"}, "device_id": {"type": "integer"}}, "required": ["contact_id", "device_id"]}, "minItems": 1, "maxItems": 5, "uniqueItems": true}, "client_reference": {"type": ["string", "null"], "pattern": "^[\\x21-\\x7E]{1,64}$", "maxLength": 64}}, "required": ["targets"], "title": "ForwardMessageRequest"}, "IngestLeadScoreEventsRequest": {"type": "object", "properties": {"events": {"type": "array", "items": {"type": "object", "properties": {"signal": {"type": "string", "enum": ["group_join", "group_leave", "group_reaction", "group_poll_vote", "link_click"]}, "owner_user_id": {"type": "integer", "minimum": 1}, "contact_id": {"type": ["integer", "null"], "minimum": 1}, "phone": {"type": ["string", "null"], "pattern": "^[0-9+\\s()\\-]+$", "minLength": 8, "maxLength": 32}, "occurred_at": {"type": "string", "format": "date-time"}, "external_id": {"type": "string", "maxLength": 255}, "scope_key": {"type": ["string", "null"], "maxLength": 255}, "meta": {"type": ["object", "null"], "properties": {"campaign_message_uid": {"type": ["string", "null"], "maxLength": 255}}}}, "required": ["signal", "owner_user_id", "occurred_at", "external_id"]}, "minItems": 1, "maxItems": 100}}, "required": ["events"], "title": "IngestLeadScoreEventsRequest"}, "KanbanSettingResource": {"type": "object", "properties": {"id": {"type": "integer"}, "user_id": {"type": "integer"}, "name": {"type": "string"}, "mode": {"type": "string"}, "stagnant_days": {"type": ["integer", "null"]}, "value_custom_field_id": {"type": ["integer", "null"]}, "profit_custom_field_id": {"type": ["integer", "null"]}, "view_mode": {"type": "string"}, "icon": {"type": ["string", "null"]}, "description": {"type": ["string", "null"]}, "is_primary": {"type": "boolean"}, "color_by_lead_score": {"type": "boolean"}, "structure": {"type": "array", "items": {}}, "stages": {"type": "array", "items": {"$ref": "#/components/schemas/KanbanStageResource"}}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}}, "required": ["id", "user_id", "name", "mode", "stagnant_days", "value_custom_field_id", "profit_custom_field_id", "view_mode", "icon", "description", "is_primary", "color_by_lead_score", "structure", "created_at", "updated_at"], "title": "KanbanSettingResource"}, "KanbanStageResource": {"type": "object", "properties": {"id": {"type": "integer"}, "kanban_setting_id": {"type": "integer"}, "name": {"type": "string"}, "position": {"type": "integer"}, "contacts_count": {"type": "integer"}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}}, "required": ["id", "kanban_setting_id", "name", "position", "created_at", "updated_at"], "title": "KanbanStageResource"}, "LeadScoreDistributionResource": {"type": "object", "properties": {"total": {"type": "string"}, "counts": {"type": "object", "properties": {"hot": {"type": "string"}, "warm": {"type": "string"}, "cold": {"type": "string"}, "insufficient_data": {"type": "string"}}, "required": ["hot", "warm", "cold", "insufficient_data"]}, "thresholds": {"type": "object", "properties": {"hot_threshold": {"type": "string"}, "warm_threshold": {"type": "string"}, "min_signals": {"type": "string"}}, "required": ["hot_threshold", "warm_threshold", "min_signals"]}}, "required": ["total", "counts", "thresholds"], "title": "LeadScoreDistributionResource"}, "LeadScoreEventResource": {"type": "object", "properties": {"id": {"type": "string"}, "signal": {"type": "string"}, "source": {"type": "string"}, "raw_points": {"type": "string"}, "applied_points": {"type": "string"}, "cap_reason": {"type": ["string", "null"]}, "occurred_at": {"type": ["string", "null"]}, "actor_user_id": {"type": "string"}, "reason": {"type": "string"}}, "required": ["id", "signal", "source", "raw_points", "applied_points", "cap_reason", "occurred_at"], "title": "LeadScoreEventResource"}, "LeadScoreSettingsResource": {"type": "object", "properties": {"hot_threshold": {"type": "integer"}, "warm_threshold": {"type": "integer"}, "min_signals": {"type": "integer"}, "hysteresis": {"type": "integer"}, "decay_steps": {"type": "array", "items": {"type": "object", "properties": {"days": {"type": "integer"}, "points": {"type": "integer"}}, "required": ["days", "points"]}}, "decay_enabled": {"type": "boolean"}, "rules": {"type": "array", "items": {}}}, "required": ["hot_threshold", "warm_threshold", "min_signals", "hysteresis", "decay_steps", "decay_enabled", "rules"], "title": "LeadScoreSettingsResource"}, "LengthAwarePaginator": {"type": "object", "properties": {"current_page": {"type": "integer"}, "data": {"type": "string"}, "first_page_url": {"type": "string"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer"}, "last_page_url": {"type": "string"}, "links": {"type": "object", "additionalProperties": {}}, "next_page_url": {"type": "string"}, "path": {"type": ["string", "null"]}, "per_page": {"type": "integer"}, "prev_page_url": {"type": ["string", "null"]}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer"}}, "required": ["current_page", "data", "first_page_url", "from", "last_page", "last_page_url", "links", "next_page_url", "path", "per_page", "prev_page_url", "to", "total"], "title": "LengthAwarePaginator"}, "MessageOriginEnum": {"type": "integer", "enum": [0, 1, 2, 3], "title": "MessageOriginEnum"}, "MessageResource": {"type": "object", "properties": {"chat_id": {"type": "string"}, "contact_id": {"anyOf": [{"type": "integer"}, {"type": "string", "enum": [""]}]}, "content": {"anyOf": [{"type": "array"}, {"type": "string", "enum": [""]}]}, "device_id": {"anyOf": [{"type": "integer"}, {"type": "string", "enum": [""]}]}, "error_code": {"type": "string"}, "file": {"type": "string"}, "forwarded": {"type": "integer"}, "group_id": {"anyOf": [{"type": "integer"}, {"type": "string", "enum": [""]}]}, "id": {"type": "integer"}, "origin": {"anyOf": [{"$ref": "#/components/schemas/MessageOriginEnum"}, {"type": "string", "enum": [""]}]}, "origin_id": {"anyOf": [{"type": "integer"}, {"type": "string", "enum": [""]}]}, "own": {"type": "integer"}, "reference_message": {"type": ["string", "null"]}, "reference_message_uid": {"type": ["string", "null"]}, "is_quotable": {"type": "boolean"}, "status": {"anyOf": [{"$ref": "#/components/schemas/MessageStatusEnum"}, {"type": "null"}]}, "temporal_uuid": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "text": {"type": "string"}, "time": {"type": ["string", "null"]}, "type": {"anyOf": [{"$ref": "#/components/schemas/MessageTypeEnum"}, {"type": "null"}]}, "uid": {"type": "string"}, "info": {"anyOf": [{"type": "array"}, {"type": "string", "enum": [""]}]}, "user_id": {"type": "integer"}, "deleted_at": {"type": ["string", "null"]}, "deleted_scope": {"type": ["string", "null"]}, "poll_results": {"type": "string"}, "event_rsvps": {"type": "string"}, "form_answers": {"type": "string"}, "reactions": {"type": "array", "items": {}}, "file_original_name": {"type": ["string", "null"]}, "client_reference": {"type": ["string", "null"]}}, "required": ["chat_id", "contact_id", "content", "device_id", "error_code", "file", "forwarded", "group_id", "id", "origin", "origin_id", "own", "reference_message", "reference_message_uid", "is_quotable", "status", "temporal_uuid", "text", "time", "type", "uid", "info", "user_id", "deleted_at", "deleted_scope", "reactions", "file_original_name", "client_reference"], "title": "MessageResource"}, "MessageStatusEnum": {"type": "integer", "enum": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "title": "MessageStatusEnum"}, "MessageTemplateStatusEnum": {"type": "string", "enum": ["PENDING", "APPROVED", "REJECTED", "PENDING_DELETION", "PAUSED", "DISABLED", "ARCHIVED"], "title": "MessageTemplateStatusEnum"}, "MessageTemplateTypeEnum": {"type": "string", "enum": ["text", "image", "document", "video", "location", "default"], "title": "MessageTemplateTypeEnum"}, "MessageTypeEnum": {"type": "integer", "enum": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "title": "MessageTypeEnum"}, "MoveBroadcastsToFolderRequest": {"type": "object", "properties": {"broadcast_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1, "maxItems": 100}, "folder_id": {"type": ["integer", "null"]}}, "required": ["broadcast_ids"], "title": "MoveBroadcastsToFolderRequest"}, "MoveContactStageRequest": {"type": "object", "properties": {"contact_id": {"type": "integer"}, "stage_id": {"type": "integer"}}, "required": ["contact_id", "stage_id"], "title": "MoveContactStageRequest"}, "NodeResource": {"type": "object", "properties": {"uuid": {"type": "string"}, "flow_id": {"type": "string"}, "type": {"type": "integer"}, "action": {"type": "string"}, "value": {"type": "string"}, "next_uuid": {"type": "string"}}, "required": ["uuid", "flow_id", "type", "action", "value", "next_uuid"], "title": "NodeResource"}, "PaymentEventTypeEnum": {"type": "string", "enum": ["approved", "pending", "rejected", "cancelled", "refunded", "chargeback"], "title": "PaymentEventTypeEnum"}, "PaymentProductResource": {"type": "object", "properties": {"external_product_id": {"type": "string"}, "name": {"type": ["string", "null"]}}, "required": ["external_product_id", "name"], "title": "PaymentProductResource"}, "PublicMessageResource": {"type": "object", "properties": {"id": {"type": "integer"}, "contact_id": {"type": ["integer", "null"]}, "device_id": {"type": ["integer", "null"]}, "direction": {"type": "string", "enum": ["outbound", "inbound"]}, "type": {"type": "string", "enum": ["text", "image", "video", "document", "sticker", "contact", "audio", "note", "action", "invalid", "interactive", "location", "voice_call", "video_call", "event", "button", "template", "notification", "option_list", "template_button_reply", "poll", "whatsapp_form", "call_permission_request", "call_permission_reply", "request_contact_info"]}, "status": {"type": ["string", "null"], "enum": ["sent", "delivered", "read", "failed", "queued", null]}, "error": {"type": ["object", "null"], "properties": {"code": {"type": ["integer", "null"]}, "title": {"type": ["string", "null"]}, "reason": {"type": ["string", "null"]}}, "required": ["code", "title", "reason"]}, "client_reference": {"type": ["string", "null"]}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}}, "required": ["id", "contact_id", "device_id", "direction", "type", "status", "error", "client_reference", "created_at", "updated_at"], "title": "PublicMessageResource"}, "QuickReplyResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "message": {"type": "string"}, "file": {"type": "string"}, "type": {"$ref": "#/components/schemas/MessageTypeEnum"}, "visibility": {"$ref": "#/components/schemas/QuickReplyVisibilityEnum"}, "agents": {"type": "object", "additionalProperties": {}}, "user_id": {"type": "integer"}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}}, "required": ["id", "name", "message", "file", "type", "visibility", "agents", "user_id", "created_at", "updated_at"], "title": "QuickReplyResource"}, "QuickReplyVisibilityEnum": {"type": "integer", "enum": [1, 2, 3], "title": "QuickReplyVisibilityEnum"}, "RemoveContactStageRequest": {"type": "object", "properties": {"contact_id": {"type": "integer"}}, "required": ["contact_id"], "title": "RemoveContactStageRequest"}, "ReorderKanbanStagesRequest": {"type": "object", "properties": {"stage_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1, "uniqueItems": true}}, "required": ["stage_ids"], "title": "ReorderKanbanStagesRequest"}, "SaleResource": {"type": "object", "properties": {"id": {"type": "integer"}, "occurred_at": {"type": "string"}, "platform": {"type": "string"}, "product_name": {"type": ["string", "null"]}, "kind": {"type": "string"}, "event_type": {"type": ["string", "null"]}, "amount_minor": {"type": "integer"}, "currency": {"type": "string"}, "attribution": {"type": "string"}, "buyer": {"type": ["object", "null"], "properties": {"contact_id": {"type": ["integer", "null"]}, "name": {"type": ["string", "null"]}, "phone": {"type": ["string", "null"]}}, "required": ["contact_id", "name", "phone"]}}, "required": ["id", "occurred_at", "platform", "product_name", "kind", "event_type", "amount_minor", "currency", "attribution", "buyer"], "title": "SaleResource"}, "SalesMetricsResource": {"type": "object", "properties": {"window": {"type": "string"}, "currencies": {"type": "string"}, "distinct_buyers": {"type": "string"}, "repeat_purchase_rate": {"type": "string"}}, "required": ["window", "currencies", "distinct_buyers", "repeat_purchase_rate"], "title": "SalesMetricsResource"}, "SaveWhatsappFormRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 120}, "definition": {"type": "object", "properties": {"screens": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "string", "maxLength": 64}, "title": {"type": ["string", "null"], "maxLength": 4096}, "cta": {"type": ["string", "null"], "maxLength": 4096}, "next": {"type": ["string", "null"], "maxLength": 64}, "routes": {"type": ["object", "null"], "properties": {"field": {"type": ["string", "null"], "maxLength": 64}, "groups": {"type": ["array", "null"], "items": {"type": "object", "properties": {"to": {"type": ["string", "null"], "maxLength": 64}, "options": {"type": ["array", "null"], "items": {"type": "string", "maxLength": 64}, "maxItems": 200}}}, "maxItems": 50}}}, "items": {"type": "array", "items": {"type": "object", "properties": {"type": {"type": "string"}, "name": {"type": "string", "maxLength": 64}, "id": {"type": ["string", "null"], "maxLength": 64}, "label": {"type": ["string", "null"], "maxLength": 4096}, "url": {"type": ["string", "null"], "maxLength": 4096}, "src": {"type": ["string", "null"], "maxLength": 440000}, "options": {"type": ["array", "null"], "items": {"type": "object", "properties": {"id": {"type": ["string", "null"], "maxLength": 4096}, "title": {"type": ["string", "null"], "maxLength": 4096}}}, "maxItems": 200}, "tagMap": {"type": ["array", "null"], "items": {"type": ["string", "null"], "maxLength": 191}}}, "required": ["type"]}, "maxItems": 100}}, "required": ["id"]}, "maxItems": 20}}, "required": ["screens"]}, "expected_updated_at": {"type": ["string", "null"]}}, "required": ["definition"], "title": "SaveWhatsappFormRequest"}, "SendDirectMessageRequest": {"type": "object", "properties": {"device_id": {"type": "integer"}, "text": {"type": "string"}, "contact_id": {"type": "integer"}, "file": {"type": "string", "description": "Archivo del mensaje: el nombre de un archivo ya subido a tu cuenta o la URL pública de un archivo (te recomendamos `https://`), que WhatsApp o el proveedor descarga; admite hasta 4096 caracteres. Si empieza con `http`, en mayúsculas o minúsculas, tiene que ser una URL `http://` o `https://`; si no, la respuesta es 422. Consulta la sección «Enviar un archivo por URL».", "pattern": "^(?:[Hh][Tt][Tt][Pp][Ss]?:\\/\\/.+|(?!\\.\\.?$)(?![Hh][Tt][Tt][Pp])[^\\/\\\\\\x00]+)$", "maxLength": 4096}, "file_type": {"type": ["string", "null"], "description": "Tipo del archivo. Es obligatorio cuando `file` es una URL que no termina en una extensión reconocida; si lo envías, manda sobre la extensión. Valores: `image`, `video`, `audio`, `document`, `sticker`. Consulta la sección «Enviar un archivo por URL».", "enum": ["image", "video", "audio", "document", "sticker", null]}, "file_name": {"type": ["string", "null"], "description": "Nombre con el que el contacto ve un documento, con su extensión (por ejemplo `factura.pdf`), de hasta 255 caracteres. Es obligatorio al enviar un documento por URL que no termina en una extensión de la lista. Consulta la sección «Enviar un archivo por URL».", "minLength": 1, "maxLength": 255}, "temporal_uuid": {"type": "string"}, "local_id": {"type": ["string", "null"], "maxLength": 255}, "note": {"type": "boolean"}, "client_reference": {"type": ["string", "null"], "pattern": "^[\\x21-\\x7E]{1,64}$", "maxLength": 64}}, "required": ["device_id", "contact_id"], "title": "SendDirectMessageRequest"}, "SendMessageRequest": {"type": "object", "properties": {"phone": {"type": "string", "minLength": 1}, "whatsapp_id": {"type": "string", "minLength": 1}, "device_id": {"type": "integer"}, "text": {"type": "string"}, "contact_id": {"type": "integer"}, "file": {"type": "string", "description": "Archivo del mensaje: el nombre de un archivo ya subido a tu cuenta o la URL pública de un archivo (te recomendamos `https://`), que WhatsApp o el proveedor descarga; admite hasta 4096 caracteres. Si empieza con `http`, en mayúsculas o minúsculas, tiene que ser una URL `http://` o `https://`; si no, la respuesta es 422. Consulta la sección «Enviar un archivo por URL».", "pattern": "^(?:[Hh][Tt][Tt][Pp][Ss]?:\\/\\/.+|(?!\\.\\.?$)(?![Hh][Tt][Tt][Pp])[^\\/\\\\\\x00]+)$", "maxLength": 4096}, "file_type": {"type": ["string", "null"], "description": "Tipo del archivo. Es obligatorio cuando `file` es una URL que no termina en una extensión reconocida; si lo envías, manda sobre la extensión. Valores: `image`, `video`, `audio`, `document`, `sticker`. Consulta la sección «Enviar un archivo por URL».", "enum": ["image", "video", "audio", "document", "sticker", null]}, "file_name": {"type": ["string", "null"], "description": "Nombre con el que el contacto ve un documento, con su extensión (por ejemplo `factura.pdf`), de hasta 255 caracteres. Es obligatorio al enviar un documento por URL que no termina en una extensión de la lista. Consulta la sección «Enviar un archivo por URL».", "minLength": 1, "maxLength": 255}, "temporal_uuid": {"type": "string"}, "note": {"type": "boolean"}, "options": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "string", "minLength": 1, "maxLength": 200}, "label": {"type": "string", "pattern": "\\S", "minLength": 1}}}, "minItems": 1, "maxItems": 10}, "reference_message_uid": {"type": ["string", "null"], "maxLength": 255}, "client_reference": {"type": ["string", "null"], "pattern": "^[\\x21-\\x7E]{1,64}$", "maxLength": 64}, "link_preview": {"type": "boolean"}, "link_preview_meta": {"type": "object", "properties": {"url": {"type": "string", "format": "uri", "maxLength": 2048}, "title": {"type": ["string", "null"], "maxLength": 200}, "description": {"type": ["string", "null"], "maxLength": 500}, "image_url": {"type": ["string", "null"], "format": "uri", "maxLength": 2048}, "domain": {"type": "string", "maxLength": 253}}}}, "required": ["device_id", "contact_id"], "title": "SendMessageRequest"}, "SendWhatsappFormRequest": {"type": "object", "properties": {"form_id": {"type": "integer", "minimum": 1}, "device_id": {"type": "integer", "minimum": 1}, "text": {"type": "string", "minLength": 1, "maxLength": 1024}, "button_text": {"type": "string", "minLength": 1, "maxLength": 30}, "client_reference": {"type": ["string", "null"], "pattern": "^[\\x21-\\x7E]{1,64}$", "maxLength": 64}}, "required": ["form_id", "device_id"], "title": "SendWhatsappFormRequest"}, "StoreBroadcastFolderRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 255}}, "required": ["name"], "title": "StoreBroadcastFolderRequest"}, "StoreContactCardRequest": {"type": "object", "properties": {"device_id": {"type": "integer"}, "contact_card_ids": {"type": "array", "items": {"type": "integer"}, "minItems": 1, "maxItems": 5, "uniqueItems": true}, "client_reference": {"type": ["string", "null"], "pattern": "^[\\x21-\\x7E]{1,64}$", "maxLength": 64}}, "required": ["device_id", "contact_card_ids"], "title": "StoreContactCardRequest"}, "StoreContactNoteRequest": {"type": "object", "properties": {"body": {"type": "string", "maxLength": 2000}}, "required": ["body"], "title": "StoreContactNoteRequest"}, "StoreContactRequest": {"type": "object", "properties": {"phone": {"type": "string"}, "whatsapp_id": {"type": "string"}, "name": {"type": ["string", "null"]}, "email": {"type": ["string", "null"], "format": "email"}, "image": {"type": ["string", "null"]}, "deviceId": {"type": ["integer", "null"]}}, "title": "StoreContactRequest"}, "StoreFolderRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 255}, "parent_id": {"type": ["integer", "null"]}}, "required": ["name"], "title": "StoreFolderRequest"}, "StoreKanbanSettingRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 50}, "mode": {"type": "string", "enum": ["tags", "stages"]}, "structure": {"type": ["array", "null"], "items": {"type": "object", "properties": {"tag_id": {"type": "integer"}, "position": {"type": "integer", "minimum": 0}}, "required": ["tag_id", "position"]}, "maxItems": 15}, "stages": {"type": ["array", "null"], "items": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 50}}}, "maxItems": 15}, "stagnant_days": {"type": ["integer", "null"], "minimum": 1, "maximum": 65535}, "view_mode": {"type": ["string", "null"], "enum": ["compact", "extended", null]}, "icon": {"type": ["string", "null"], "enum": ["target", "filter", "trending-up", "users", "briefcase", "shopping-cart", "heart", "star", "flag", "rocket", "layers", "zap", null]}, "description": {"type": ["string", "null"], "maxLength": 200}, "is_primary": {"type": "boolean"}, "color_by_lead_score": {"type": "boolean"}}, "required": ["name"], "title": "StoreKanbanSettingRequest"}, "StoreKanbanStageRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 50}, "after_stage_id": {"type": ["integer", "null"]}}, "required": ["name"], "title": "StoreKanbanStageRequest"}, "StoreLeadScoreAdjustmentRequest": {"type": "object", "properties": {"delta": {"type": "integer", "minimum": -100, "maximum": 100}, "reason": {"type": "string", "minLength": 3, "maxLength": 255}}, "required": ["delta", "reason"], "title": "StoreLeadScoreAdjustmentRequest"}, "StoreMessageReactionRequest": {"type": "object", "properties": {"emoji": {"type": "string", "maxLength": 32}}, "required": ["emoji"], "title": "StoreMessageReactionRequest"}, "StoreMessageTemplateRequest": {"type": "object", "properties": {"name": {"type": "string"}, "language_code": {"type": "string", "enum": ["af", "sq", "ar", "ar_EG", "ar_AE", "ar_LB", "ar_MA", "ar_QA", "az", "be_BY", "bn", "bn_IN", "bg", "ca", "zh_CN", "zh_HK", "zh_TW", "hr", "cs", "da", "prs_AF", "nl", "nl_BE", "en", "en_GB", "en_US", "en_AE", "en_AU", "en_CA", "en_GH", "en_IE", "en_IN", "en_JM", "en_MY", "en_NZ", "en_QA", "en_SG", "en_UG", "en_ZA", "et", "fil", "fi", "fr", "fr_BE", "fr_CA", "fr_CH", "fr_CI", "fr_MA", "ka", "de", "de_AT", "de_CH", "el", "gu", "ha", "he", "hi", "hu", "id", "ga", "it", "ja", "kn", "kk", "rw_RW", "ko", "ky_KG", "lo", "lv", "lt", "mk", "ms", "ml", "mr", "nb", "ps_AF", "fa", "pl", "pt_BR", "pt_PT", "pa", "ro", "ru", "sr", "si_LK", "sk", "sl", "es", "es_AR", "es_CL", "es_CO", "es_CR", "es_DO", "es_EC", "es_HN", "es_MX", "es_PA", "es_PE", "es_ES", "es_UY", "sw", "sv", "ta", "te", "th", "tr", "uk", "ur", "uz", "vi", "zu"]}, "category": {"type": "string", "enum": ["UTILITY", "MARKETING", "AUTHENTICATION"]}, "type": {"type": "string", "enum": ["text", "image", "document", "video", "location", "default"]}, "header": {"type": ["string", "null"]}, "file": {"type": "string"}, "body": {"type": "string"}, "params": {"type": ["array", "null"], "items": {"type": "string"}}, "footer": {"type": ["string", "null"]}, "buttons": {"type": ["array", "null"], "items": {"type": "object", "properties": {"text": {"type": "string"}, "type": {"type": "string", "enum": ["QUICK_REPLY", "URL", "PHONE_NUMBER"]}, "url": {"type": "string", "format": "uri"}, "phone_number": {"type": "string"}}}, "maxItems": 3}}, "required": ["name", "language_code", "category", "type", "body"], "title": "StoreMessageTemplateRequest"}, "StoreWebhookSubscriptionRequest": {"type": "object", "properties": {"url": {"type": "string", "format": "uri", "maxLength": 2048}, "description": {"type": ["string", "null"], "maxLength": 255}, "events": {"type": "array", "items": {"type": "string", "enum": ["message.received", "flow.completed", "broadcast.finished", "contact.stage_changed", "message.status_changed", "conversation.closed", "conversation.assigned", "contact.tag_added", "broadcast.paused", "contact.tag_removed", "contact.created", "template.status_changed", "flow.failed", "whatsapp_form.completed", "*"]}, "minItems": 1, "maxItems": 15, "uniqueItems": true}}, "required": ["url", "events"], "title": "StoreWebhookSubscriptionRequest"}, "StoreWhatsappFormRequest": {"type": "object", "properties": {"device_id": {"type": "integer", "minimum": 1}, "device_ids": {"type": "array", "items": {"type": "integer", "minimum": 1}, "maxItems": 50}, "template_key": {"type": "string"}}, "required": ["device_id", "template_key"], "title": "StoreWhatsappFormRequest"}, "TagResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "description": {"type": "string"}, "color": {"type": ["string", "null"]}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}, "contact_count": {"anyOf": [{"type": "string"}, {"type": "integer", "minimum": 0}]}}, "required": ["id", "name", "description", "color", "created_at", "updated_at", "contact_count"], "title": "TagResource"}, "TemplateResource": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "text": {"type": "string"}, "header": {"type": "string"}, "footer": {"type": "string"}, "observation": {"type": "string"}, "uid": {"type": "string"}, "category": {"type": "string"}, "type": {"anyOf": [{"$ref": "#/components/schemas/MessageTemplateTypeEnum"}, {"type": "string", "enum": [""]}]}, "status": {"anyOf": [{"$ref": "#/components/schemas/MessageTemplateStatusEnum"}, {"type": "string", "enum": [""]}]}, "language_code": {"type": "string"}, "upload_session_id": {"type": "string"}, "header_handle": {"type": "string"}, "file": {"type": "string"}, "params": {"anyOf": [{"type": "array"}, {"type": "string", "enum": [""]}]}, "buttons": {"anyOf": [{"type": "array"}, {"type": "string", "enum": [""]}]}, "user_id": {"type": "integer"}, "device_id": {"type": "integer"}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "recategorized_at": {"type": ["string", "null"], "format": "date-time"}, "quick_reply_buttons": {"type": "array", "items": {}}, "waba_id": {"type": ["string", "null"]}, "belongs_to_current_device": {"type": "boolean"}}, "required": ["id", "name", "text", "header", "footer", "observation", "uid", "category", "type", "status", "language_code", "upload_session_id", "header_handle", "file", "params", "buttons", "user_id", "device_id", "created_at", "recategorized_at", "quick_reply_buttons", "waba_id", "belongs_to_current_device"], "title": "TemplateResource"}, "Ticket": {"type": "object", "properties": {"id": {"type": "integer"}, "user_id": {"type": "integer"}, "contact_id": {"type": ["integer", "null"]}, "title": {"type": "string"}, "description": {"type": ["string", "null"]}, "deadline": {"type": ["integer", "null"]}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}, "actor_user_id": {"type": ["integer", "null"]}}, "required": ["id", "user_id", "contact_id", "title", "description", "deadline", "created_at", "updated_at", "actor_user_id"], "title": "Ticket"}, "UpdateBroadcastFolderRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 255}}, "required": ["name"], "title": "UpdateBroadcastFolderRequest"}, "UpdateContactRequest": {"type": "object", "properties": {"name": {"type": ["string", "null"], "maxLength": 255}, "email": {"type": ["string", "null"], "format": "email", "maxLength": 255}, "phone": {"type": ["string", "null"], "maxLength": 20}, "notes": {"type": ["string", "null"], "maxLength": 2500}, "status": {"type": "integer"}, "adviser_id": {"type": ["integer", "null"]}, "active_conversation": {"type": "boolean"}, "favorite": {"type": "boolean"}, "fixed": {"type": "boolean"}, "image": {"type": ["string", "null"]}, "can_execute_flows": {"type": "boolean"}, "manually_unread": {"type": "boolean"}}, "title": "UpdateContactRequest"}, "UpdateFolderRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 255}, "parent_id": {"type": ["integer", "null"]}}, "title": "UpdateFolderRequest"}, "UpdateKanbanSettingRequest": {"type": "object", "properties": {"name": {"type": ["string", "null"], "maxLength": 50}, "mode": {"type": "string"}, "structure": {"type": ["array", "null"], "items": {"type": "object", "properties": {"tag_id": {"type": "integer"}, "position": {"type": "integer", "minimum": 0}}, "required": ["tag_id", "position"]}, "maxItems": 15}, "stagnant_days": {"type": ["integer", "null"], "minimum": 1, "maximum": 65535}, "view_mode": {"type": ["string", "null"], "enum": ["compact", "extended", null]}, "icon": {"type": ["string", "null"], "enum": ["target", "filter", "trending-up", "users", "briefcase", "shopping-cart", "heart", "star", "flag", "rocket", "layers", "zap", null]}, "description": {"type": ["string", "null"], "maxLength": 200}, "is_primary": {"type": "boolean"}, "color_by_lead_score": {"type": "boolean"}}, "title": "UpdateKanbanSettingRequest"}, "UpdateKanbanStageRequest": {"type": "object", "properties": {"name": {"type": "string", "maxLength": 50}}, "required": ["name"], "title": "UpdateKanbanStageRequest"}, "UpdateMessageTemplateRequest": {"type": "object", "properties": {"device_id": {"type": "integer"}, "category": {"type": "string", "enum": ["UTILITY", "MARKETING", "AUTHENTICATION"]}, "type": {"type": "string", "enum": ["text", "image", "document", "video", "location", "default"]}, "header": {"type": ["string", "null"]}, "file": {"type": "string"}, "body": {"type": "string"}, "params": {"type": ["array", "null"], "items": {"type": "string"}}, "footer": {"type": ["string", "null"]}, "buttons": {"type": ["array", "null"], "items": {"type": "object", "properties": {"text": {"type": "string"}, "type": {"type": "string", "enum": ["QUICK_REPLY", "URL", "PHONE_NUMBER"]}, "url": {"type": "string", "format": "uri"}, "phone_number": {"type": "string"}}}, "maxItems": 3}}, "required": ["device_id", "category", "type", "body"], "title": "UpdateMessageTemplateRequest"}, "UpdateWebhookSubscriptionRequest": {"type": "object", "properties": {"url": {"type": "string", "format": "uri", "maxLength": 2048}, "description": {"type": ["string", "null"], "maxLength": 255}, "events": {"type": "array", "items": {"type": "string", "enum": ["message.received", "flow.completed", "broadcast.finished", "contact.stage_changed", "message.status_changed", "conversation.closed", "conversation.assigned", "contact.tag_added", "broadcast.paused", "contact.tag_removed", "contact.created", "template.status_changed", "flow.failed", "whatsapp_form.completed", "*"]}, "minItems": 1, "maxItems": 15, "uniqueItems": true}, "active": {"type": "boolean"}}, "title": "UpdateWebhookSubscriptionRequest"}, "User": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "email": {"type": "string"}, "stripe_customer_id": {"type": ["string", "null"]}, "payment_provider": {"type": ["integer", "null"]}, "image": {"type": ["string", "null"]}, "phone": {"type": ["integer", "null"]}, "email_verified_at": {"type": ["string", "null"], "format": "date-time"}, "country_code": {"type": ["string", "null"]}, "country_name": {"type": ["string", "null"]}, "first_login_at": {"type": ["string", "null"]}, "last_login_at": {"type": ["string", "null"]}, "owner_id": {"type": ["integer", "null"]}, "advisor_scope": {"type": ["integer", "null"]}, "admin": {"type": ["boolean", "null"]}, "status": {"type": ["integer", "null"]}, "payment_status": {"type": ["integer", "null"]}, "mac_enforcement_enabled": {"type": "integer"}, "timezone": {"type": "string"}, "plan_name": {"type": ["string", "null"]}, "trial": {"type": ["integer", "null"]}, "payment_till": {"type": ["string", "null"], "format": "date-time"}, "subscription_count": {"type": ["integer", "null"]}, "plan_id": {"type": ["integer", "null"]}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}, "show_advisor_name": {"type": "integer"}, "password_set_at": {"type": ["string", "null"]}, "alert_plan_blocked_notified_at": {"type": ["string", "null"]}, "card_prompt_pending": {"type": ["integer", "null"]}, "trial_billing_cycle": {"type": ["string", "null"]}, "locale": {"type": "string"}, "signup_ip": {"type": ["string", "null"]}, "trial_extended_at": {"type": ["string", "null"]}, "selected_plan_id": {"type": ["integer", "null"]}, "fbp": {"type": ["string", "null"]}, "fbc": {"type": ["string", "null"]}, "signup_user_agent": {"type": ["string", "null"]}, "signup_url": {"type": ["string", "null"]}, "agent_locked_at": {"type": ["string", "null"]}, "theme": {"type": "string"}, "hotmart_migrated_at": {"type": ["string", "null"]}, "stripe_migration_incomplete_at": {"type": ["string", "null"]}, "stripe_migration_incomplete_reason": {"type": ["string", "null"]}}, "required": ["id", "name", "email", "stripe_customer_id", "payment_provider", "image", "phone", "email_verified_at", "country_code", "country_name", "first_login_at", "last_login_at", "owner_id", "advisor_scope", "admin", "status", "payment_status", "mac_enforcement_enabled", "timezone", "plan_name", "trial", "payment_till", "subscription_count", "plan_id", "created_at", "updated_at", "show_advisor_name", "password_set_at", "alert_plan_blocked_notified_at", "card_prompt_pending", "trial_billing_cycle", "locale", "signup_ip", "trial_extended_at", "selected_plan_id", "fbp", "fbc", "signup_user_agent", "signup_url", "agent_locked_at", "theme", "hotmart_migrated_at", "stripe_migration_incomplete_at", "stripe_migration_incomplete_reason"], "title": "User"}, "UserResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "email": {"type": "string"}, "owner_id": {"type": "string"}, "advisor_scope": {"type": "string"}, "created_at": {"type": "string"}, "updated_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}}, "required": ["id", "name", "email", "owner_id", "advisor_scope", "created_at", "updated_at"], "title": "UserResource"}, "WebhookDeliveryResource": {"type": "object", "properties": {"uuid": {"type": "string"}, "event_id": {"type": "string"}, "event_type": {"type": "string"}, "attempt": {"type": "integer"}, "status": {"type": "string"}, "http_status": {"type": ["integer", "null"]}, "duration_ms": {"type": ["integer", "null"]}, "error": {"type": ["string", "null"]}, "next_attempt_at": {"type": ["string", "null"]}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}}, "required": ["uuid", "event_id", "event_type", "attempt", "status", "http_status", "duration_ms", "error", "next_attempt_at", "created_at", "updated_at"], "title": "WebhookDeliveryResource"}, "WebhookSubscriptionResource": {"type": "object", "properties": {"uuid": {"type": "string"}, "url": {"type": "string"}, "description": {"type": ["string", "null"]}, "events": {"type": "array", "items": {}}, "active": {"type": "boolean"}, "inactive_reason": {"type": ["string", "null"]}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}}, "required": ["uuid", "url", "description", "events", "active", "inactive_reason", "created_at", "updated_at"], "title": "WebhookSubscriptionResource"}, "WhatsappForm": {"type": "object", "properties": {"id": {"type": "integer"}, "user_id": {"type": "integer"}, "workspace_id": {"type": ["integer", "null"]}, "phone_number_id": {"type": "string"}, "family_id": {"type": "integer"}, "name": {"type": "string"}, "category": {"type": "string"}, "status": {"type": "string"}, "version": {"type": "integer"}, "parent_flow_id": {"type": ["integer", "null"]}, "definition": {"type": "array", "items": {}}, "flow_json": {"type": ["array", "null"], "items": {}}, "flow_json_hash": {"type": ["string", "null"]}, "fields": {"type": ["array", "null"], "items": {}}, "mapping": {"type": ["array", "null"], "items": {}}, "tag_rules": {"type": ["array", "null"], "items": {}}, "has_endpoint": {"type": "boolean"}, "first_screen": {"type": ["string", "null"]}, "first_screen_dynamic": {"type": "boolean"}, "meta_flow_id": {"type": ["string", "null"]}, "validation_errors": {"type": ["array", "null"], "items": {}}, "lint_errors_count": {"type": "integer"}, "retained_reason": {"type": ["string", "null"]}, "published_at": {"type": ["string", "null"], "format": "date-time"}, "deprecated_at": {"type": ["string", "null"], "format": "date-time"}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}, "deleted_at": {"type": ["string", "null"], "format": "date-time"}, "actor_user_id": {"type": ["integer", "null"]}}, "required": ["id", "user_id", "workspace_id", "phone_number_id", "family_id", "name", "category", "status", "version", "parent_flow_id", "definition", "flow_json", "flow_json_hash", "fields", "mapping", "tag_rules", "has_endpoint", "first_screen", "first_screen_dynamic", "meta_flow_id", "validation_errors", "lint_errors_count", "retained_reason", "published_at", "deprecated_at", "created_at", "updated_at", "deleted_at", "actor_user_id"], "title": "WhatsappForm"}, "WhatsappFormResource": {"type": "object", "properties": {"id": {"type": "integer"}, "family_id": {"type": "integer"}, "name": {"type": "string"}, "label": {"type": "string"}, "category": {"type": "string"}, "status": {"type": "string"}, "version": {"type": "integer"}, "definition": {"type": "array", "items": {}}, "fields": {"type": ["array", "null"], "items": {}}, "mapping": {"type": ["array", "null"], "items": {}}, "tag_rules": {"type": ["array", "null"], "items": {}}, "has_endpoint": {"type": "boolean"}, "first_screen": {"type": ["string", "null"]}, "first_screen_dynamic": {"type": "boolean"}, "lint_errors_count": {"type": "integer"}, "draft_id": {"type": "integer"}, "draft_version": {"type": "integer"}, "sends": {"type": "integer"}, "responses": {"type": "integer"}, "meta_flow_id": {"type": ["string", "null"]}, "flow_json": {"type": ["array", "null"], "items": {}}, "validation_errors": {"type": ["array", "null"], "items": {}}, "published_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}}, "required": ["id", "family_id", "name", "label", "category", "status", "version", "has_endpoint", "first_screen", "first_screen_dynamic", "lint_errors_count", "meta_flow_id", "published_at", "updated_at"], "title": "WhatsappFormResource"}, "WhatsappFormRun": {"type": "object", "properties": {"id": {"type": "integer"}, "user_id": {"type": "integer"}, "workspace_id": {"type": ["integer", "null"]}, "flow_token": {"type": "string"}, "whatsapp_form_id": {"type": "integer"}, "contact_id": {"type": "integer"}, "conversation_id": {"type": ["integer", "null"]}, "automation_run_id": {"type": ["integer", "null"]}, "node_id": {"type": ["string", "null"]}, "origin": {"type": "string"}, "channel": {"type": ["string", "null"]}, "message_id": {"type": ["string", "null"]}, "reply_message_id": {"type": ["string", "null"]}, "status": {"type": "string"}, "reason": {"type": ["string", "null"]}, "context": {"type": ["array", "null"], "items": {}}, "response_json": {"type": ["array", "null"], "items": {}}, "partial_json": {"type": ["array", "null"], "items": {}}, "last_screen_id": {"type": ["string", "null"]}, "completed_after_expiry": {"type": "boolean"}, "output_id": {"type": ["string", "null"]}, "output_routed_at": {"type": ["string", "null"], "format": "date-time"}, "sent_at": {"type": ["string", "null"], "format": "date-time"}, "delivered_at": {"type": ["string", "null"], "format": "date-time"}, "read_at": {"type": ["string", "null"], "format": "date-time"}, "expires_at": {"type": ["string", "null"], "format": "date-time"}, "responded_at": {"type": ["string", "null"], "format": "date-time"}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}, "environment": {"type": ["string", "null"]}}, "required": ["id", "user_id", "workspace_id", "flow_token", "whatsapp_form_id", "contact_id", "conversation_id", "automation_run_id", "node_id", "origin", "channel", "message_id", "reply_message_id", "status", "reason", "context", "response_json", "partial_json", "last_screen_id", "completed_after_expiry", "output_id", "output_routed_at", "sent_at", "delivered_at", "read_at", "expires_at", "responded_at", "created_at", "updated_at", "environment"], "title": "WhatsappFormRun"}, "WhatsappFormTemplate": {"type": "object", "properties": {"id": {"type": "integer"}, "key": {"type": "string"}, "title": {"type": "string"}, "description": {"type": "string"}, "category": {"type": "string"}, "definition": {"type": "array", "items": {}}, "sort": {"type": "integer"}, "created_at": {"type": ["string", "null"], "format": "date-time"}, "updated_at": {"type": ["string", "null"], "format": "date-time"}}, "required": ["id", "key", "title", "description", "category", "definition", "sort", "created_at", "updated_at"], "title": "WhatsappFormTemplate"}}, "responses": {"ValidationException": {"description": "Unprocessable Content", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}}}}, "AuthenticationException": {"description": "Unauthorized", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "AuthorizationException": {"description": "Forbidden", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "ModelNotFoundException": {"description": "Not Found", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}}}, "webhooks": {"message.received": {"post": {"summary": "message.received", "description": "Un contacto le escribió a un número de WhatsApp de la cuenta.\n\n`device_id` es el número de tu cuenta que recibió el mensaje: el mismo `device_id` que mandas para responder por ese número. Es `null` si el mensaje no tiene número asociado.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "object", "properties": {"message": {"type": "object", "properties": {"type": {"type": "string", "enum": ["text", "image", "video", "document", "sticker", "contact", "audio", "note", "action", "invalid", "interactive", "location", "voice_call", "video_call", "event", "button", "template", "notification", "option_list", "template_button_reply", "poll", "whatsapp_form", "call_permission_request", "call_permission_reply", "request_contact_info"]}}}}}}}, "example": {"id": "evt_000000000000000000000001", "type": "message.received", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"message": {"id": 1001, "type": "text", "text": "Hola, quiero más información", "media": null}, "contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}, "receiver": {"phone": "+5491100000001"}, "device_id": 4521}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "flow.completed": {"post": {"summary": "flow.completed", "description": "Un contacto terminó un flujo de automatización.\n\nSe envía una sola vez por cada ejecución de un flujo, cuando termina con éxito. No se envía si la ejecución se cortó, se canceló, quedó bloqueada o falló. `contact` es `null` si la ejecución no tiene un contacto asociado. Un flujo muy usado puede generar muchos eventos seguidos.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000003", "type": "flow.completed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"flow": {"id": 3001, "name": "Flujo de ejemplo"}, "contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "broadcast.finished": {"post": {"summary": "broadcast.finished", "description": "Una campaña llegó a su estado final (enviada, fallida o con fallos parciales), con sus conteos.\n\n`status` es `success`, `failed` o `partially_failed`. `reason` dice por qué terminó: `completed` (se enviaron todas las páginas), `cancelled` (se cerró una campaña pausada), `template_rejected` (Meta rechazó la plantilla, o su categoría cambió, mientras la campaña esperaba), `approval_expired` (la plantilla no se aprobó a tiempo), `mac_lockout` (la cuenta alcanzó su límite de contactos activos), `no_recipients` (la audiencia quedó vacía) o `error` (el envío no pudo despacharse). `totals` son los conteos del envío: `processed` (destinatarios procesados), `failed` y `skipped_unreachable` (destinatarios que el canal no puede alcanzar); valen 0 si la campaña terminó antes de enviar. Se emite una sola vez por campaña.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000011", "type": "broadcast.finished", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"broadcast": {"id": 6001, "name": "Campaña de ejemplo"}, "status": "partially_failed", "reason": "completed", "totals": {"processed": 1200, "failed": 30, "skipped_unreachable": 12}}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "contact.stage_changed": {"post": {"summary": "contact.stage_changed", "description": "Un contacto cambió de etapa en un tablero.\n\nSe envía un evento por cada contacto que cambia de etapa en un tablero por etapas. `kind` es entry (entra al tablero, `from_stage` es null), move (pasa de una etapa a otra), exit (sale del tablero, `to_stage` es null) o stage_deleted (se reubica porque su etapa se borró; el nombre de la etapa borrada es null). No se envía si el contacto se coloca en la etapa en la que ya estaba.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000008", "type": "contact.stage_changed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}, "board": {"id": 5001, "name": "Embudo de ejemplo"}, "kind": "move", "from_stage": {"id": 6001, "name": "Nuevo", "position": 0}, "to_stage": {"id": 6002, "name": "En seguimiento", "position": 1}}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "message.status_changed": {"post": {"summary": "message.status_changed", "description": "Cambió el estado de entrega de un mensaje enviado.\n\nSe emite cuando cambia el estado de entrega de un mensaje que enviaste a un contacto, ya sea desde el chat, una automatización o un asistente de IA (incluye los enviados con clave). No se emite para mensajes de difusiones ni para mensajes recibidos. `message_id` es el id que devuelve la API, `contact_id` el del contacto y `device_id` el número de tu cuenta por el que salió el mensaje, el mismo `device_id` que usas para enviar (`null` si no tiene). `status` es `sent`, `delivered`, `read` o `failed`. `previous_status` es el estado que el mensaje tenía justo antes de este cambio y es `null` en tres casos: es el primer aviso del mensaje, es el mismo estado que `status` (por ejemplo, el proveedor confirma el `sent` que ya registró el envío) o no se pudo leer. `error` solo viene cuando `status` es `failed`: `code` es el código numérico del proveedor y `title` su título, y cualquiera de los dos puede ser `null` si el proveedor no los informa. `error.reason` es `null` cuando el fallo lo informó el proveedor; cuando Funnelchat decidió que un mensaje enviado con clave no salía (por ejemplo, por saldo insuficiente o ventana de 24 horas cerrada) trae el motivo (`device_unavailable`, `insufficient_balance`, `window_closed`, `recipient_unreachable`, `template_not_found`, `template_unresolved_placeholder`, `not_queued` o `not_sent`), `code` es `null` y `title` es un texto llano en el idioma de la cuenta. `occurred_at` es el momento en que Funnelchat registró el estado, en UTC. `client_reference` es la referencia que mandaste al enviar el mensaje (por ejemplo `pedido-1001`) y `null` si el envío no la llevaba: sirve para relacionar cada aviso con tu envío también cuando la llamada de envío no respondió. Cada estado se informa una sola vez por mensaje: si llegan varios avisos juntos se informa el más avanzado y un aviso atrasado que no cambia el estado no genera evento. Un mensaje que no llegó a salir (por ejemplo, por ventana de 24 horas cerrada) no recibe avisos de estado, salvo uno enviado con clave: ese recibe un único aviso `failed` con `previous_status` en `null`, su `error.reason` y su `client_reference`. Un mensaje enviado con clave cuyo resultado no se conoce (el proveedor no respondió o el envío se interrumpió) no recibe aviso. Un mensaje cuyo envío no empezó dentro de la hora ya no sale: pasada la hora sin resultado, su estado es `null`, o `failed` con `error.reason` `not_sent` y su aviso si su envío llega tarde. Reintentar es un envío nuevo, que sólo puede duplicar si el envío había empezado y se cortó. Un mensaje `queued` no es enviado: su resultado llega por este evento o por la consulta del mensaje. En cuentas con mucho tráfico, los eventos que excedan el límite de entrega por minuto de la cuenta se descartan. Para recibirlo debes suscribirte a `message.status_changed` de forma explícita: una suscripción a `*` no lo incluye.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000014", "type": "message.status_changed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"message_id": 1001, "contact_id": 2001, "device_id": 4521, "status": "failed", "previous_status": "sent", "error": {"code": 131047, "title": "Re-engagement message", "reason": null}, "occurred_at": "2026-10-01T12:00:00Z", "client_reference": "pedido-1001"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "conversation.closed": {"post": {"summary": "conversation.closed", "description": "Una conversación pasó a cerrada.\n\nSe envía cuando una conversación pasa de abierta a cerrada. No se envía si la conversación ya estaba cerrada ni cuando se reabre.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000004", "type": "conversation.closed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "conversation.assigned": {"post": {"summary": "conversation.assigned", "description": "Una conversación quedó asignada a una persona del equipo o a un agente de IA.\n\nSe envía cuando una conversación queda asignada a una persona del equipo (`assignee.type` = `human`) o a un agente de IA (`assignee.type` = `ai`), por cualquier camino. `assignee` trae el tipo y el nombre, nunca un identificador. No se envía al desasignar, ni cuando se vuelve a enviar el mismo asignado.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000005", "type": "conversation.assigned", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}, "assignee": {"type": "human", "name": "Agente de ejemplo"}}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "contact.tag_added": {"post": {"summary": "contact.tag_added", "description": "Un contacto recibió una etiqueta.\n\nSe envía un evento por cada contacto y etiqueta agregados, también en operaciones en bloque; no se envía si el contacto ya tenía la etiqueta. `source` indica el origen: manual, flow, bulk, import, sync, walink o ai. En operaciones en bloque grandes el límite de volumen de la cuenta puede descartar parte de los eventos.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000006", "type": "contact.tag_added", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}, "tag": {"id": 4001, "name": "Etiqueta de ejemplo"}, "source": "manual"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "broadcast.paused": {"post": {"summary": "broadcast.paused", "description": "Una campaña se pausó sola, por ejemplo porque bajó la calidad del número.\n\n`reason` es `quality_degraded` (la calidad del número bajó respecto de la del inicio, o llegó a RED) o `quality_unreadable` (no se pudo leer la calidad en tres controles seguidos). `quality` y `quality_baseline` son la calidad de Meta leída en el control y la del inicio del envío (`GREEN`, `YELLOW`, `RED`), o `null` si no se pudo leer. Sólo las campañas con envío inteligente se pausan solas. Reanudar la campaña y que se pause otra vez emite otro evento.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000007", "type": "broadcast.paused", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"broadcast": {"id": 6001, "name": "Campaña de ejemplo"}, "reason": "quality_degraded", "quality": "YELLOW", "quality_baseline": "GREEN"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "contact.tag_removed": {"post": {"summary": "contact.tag_removed", "description": "Un contacto perdió una etiqueta.\n\nSe envía un evento por cada contacto y etiqueta quitados, también en operaciones en bloque; no se envía si el contacto no tenía la etiqueta. No se envía al borrar la etiqueta, al borrar o fusionar contactos ni al desvincular etiquetas de un tablero. `source` indica el origen: manual, flow, bulk o ai. En operaciones en bloque grandes el límite de volumen de la cuenta puede descartar parte de los eventos.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000009", "type": "contact.tag_removed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}, "tag": {"id": 4001, "name": "Etiqueta de ejemplo"}, "source": "manual"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "contact.created": {"post": {"summary": "contact.created", "description": "Se creó un contacto nuevo en la cuenta.\n\nSe envía un evento por cada contacto nuevo, sea cual sea el canal: un mensaje entrante, la creación manual, una importación o la API. No se envía cuando el contacto ya existía y sólo se actualiza, ni para los contactos que la plataforma crea para sus propias notificaciones. En importaciones grandes el límite de volumen de la cuenta puede descartar parte de los eventos.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000010", "type": "contact.created", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000", "email": "contacto@example.com"}}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "template.status_changed": {"post": {"summary": "template.status_changed", "description": "Una plantilla cambió de estado de aprobación en Meta.\n\n`template` identifica la plantilla igual que `GET /templates` (`id`, `uid`, `name`, `category`). `previous_status` y `status` son los estados tal como los devuelve la API (por ejemplo `PENDING`, `APPROVED`, `REJECTED`, `PAUSED`); `previous_status` es `null` si la plantilla no tenía estado. `reason` trae la observación de rechazo (traducida como en la API y limitada a 500 caracteres) cuando el cambio es un rechazo informado al crear la plantilla, y es `null` en el resto. No se emite si Meta reenvía el estado que la plantilla ya tenía. Si una misma plantilla de Meta figura en varias cuentas, cada cuenta recibe su propio evento.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000012", "type": "template.status_changed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"template": {"id": 7001, "uid": "1234567890", "name": "plantilla_ejemplo", "category": "MARKETING"}, "previous_status": "PENDING", "status": "APPROVED", "reason": null}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "flow.failed": {"post": {"summary": "flow.failed", "description": "La ejecución de un flujo para un contacto terminó por un error.\n\nSe envía una sola vez por cada ejecución de un flujo que termina por un error, no porque llegó al final. `reason` indica el motivo y toma uno de estos valores: `node_missing` (el paso a ejecutar ya no existe), `unknown_node_type` (el paso es de un tipo no reconocido), `missing_subflow` (el flujo que debía ejecutarse dentro de otro ya no existe), `malformed_node` (el paso tiene una configuración dañada), `loop_detected` (la ejecución dio vueltas sin esperar nada) y `execution_error` (un error inesperado detuvo la ejecución). No se envía si la ejecución se canceló, quedó bloqueada o se cortó porque se editó el flujo o se unieron contactos. `contact` es `null` si la ejecución no tiene un contacto asociado.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000013", "type": "flow.failed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"flow": {"id": 3001, "name": "Flujo de ejemplo"}, "contact": {"id": 2001, "name": "Contacto de ejemplo", "phone": "+5491100000000"}, "reason": "execution_error"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "whatsapp_form.completed": {"post": {"summary": "whatsapp_form.completed", "description": "Un contacto completó un formulario de WhatsApp.\n\nSe envía cuando un contacto completa un formulario, aunque la respuesta llegue tarde. Puede llegar más de una vez con el mismo `id`: deduplica por `id`. Si el contacto vuelve a enviar el mismo formulario, no se genera otro aviso: queda la primera respuesta. Cada respuesta de texto llega con a lo sumo 600 caracteres. `form.id` es el formulario (el mismo `family_id` de la lectura de formularios) y `form.version_id` la versión que recibió el contacto. `answers` es una lista con una entrada por pregunta, en el orden del formulario: `key` es el nombre de la pregunta, `label` su etiqueta y `value` la respuesta (texto, número, `true` o `false`, una lista de textos en opción múltiple, o `null` si no la contestó). En las preguntas de lista y de opción múltiple, `value` es el id de la opción. `message_id` es el id del mensaje del formulario y es `null` si el envío no tuvo un mensaje público; `device_id` es el número de WhatsApp por el que salió, o `null` si ya no es de la cuenta. `contact_id` es `null` si el contacto se eliminó antes de que saliera el aviso (las respuestas llegan igual); si se fusionó con otro, es el id del contacto que quedó. Mientras se fusionan dos contactos, el id puede ser el del contacto que se está fusionando.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000015", "type": "whatsapp_form.completed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"form": {"id": 4001, "name": "Captar un lead", "version_id": 4002}, "message_id": 1001, "contact_id": 2001, "device_id": 5001, "answers": [{"key": "nombre", "label": "Nombre", "value": "Contacto de ejemplo"}, {"key": "intereses", "label": "Intereses", "value": ["op_a", "op_b"]}, {"key": "comentarios", "label": "Comentarios", "value": null}], "occurred_at": "2026-10-01T12:00:00Z"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}, "webhook.test": {"post": {"summary": "webhook.test", "description": "Evento de prueba enviado desde la ruta de prueba de una suscripción.", "x-fc-status": "live", "parameters": [{"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma de la entrega: `t=<timestamp>,v1=<firma>`. Se calcula sobre `t + \".\" + cuerpo crudo`.", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo de evento (igual que `type` en el cuerpo).", "schema": {"type": "string"}}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "Identificador de esta entrega; cambia en cada intento.", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_000000000000000000000002", "type": "webhook.test", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"subscription": "00000000-0000-4000-8000-000000000001", "sent_at": "2026-10-01T12:00:00Z"}}}}}, "responses": {"2XX": {"description": "Cualquier respuesta 2xx en 10 segundos o menos confirma la entrega."}}}}}}