{"openapi": "3.1.2", "info": {"title": "FunnelChat Communities", "version": "1.0.0", "description": "API de Funnelchat para gestionar desde tu propio sistema las campañas de grupos de WhatsApp de tu cuenta: sus grupos, los participantes y los envíos programados de mensajes a grupos.\n\n## Autenticación\n\nCada llamada lleva tu API key en el encabezado `Authorization: Bearer <id>|fc_live_...`. En «Try It» pegá tu key: esta documentación no usa las cookies de tu sesión.\n\n## Permisos\n\nCada operación indica el permiso que necesita. Una key solo puede llamar a las operaciones de los permisos que tiene.\n\n- `communities:read` (Leer): llama a las operaciones de lectura, que consultan datos de tu cuenta sin cambiar nada.\n- `communities:write` (Escribir): incluye leer; en v0, `communities:write` solo administra suscripciones de webhooks (crear, editar, borrar, rotar el secreto y probar).\n- `communities:send` (Enviar): incluye escribir y leer, pero en v0 no hay ninguna operación de envío disponible.\n- `communities:operate` (Operar): en v0 no habilita ninguna operación.\n\n## Errores de la API key\n\n- `401` con `error: unauthenticated`: falta la key, o es inválida, venció o fue revocada. La respuesta trae `WWW-Authenticate: Bearer`.\n- `403` con `error: permission_denied`: la key no tiene el permiso que necesita la operación.\n- `403` con `error: route_not_available`: la operación no está disponible para API keys.\n- `403` con `error: use_public_endpoint`: la key llegó por una dirección que no es la pública. El mensaje dice cuál usar.\n- `429` con `error: daily_cap_exceeded`: la key alcanzó su límite diario de llamadas. La respuesta trae `Retry-After` con los segundos hasta que se renueve.\n- `503` con `error: gate_unavailable`: no se pudo verificar la key en este momento. La respuesta trae `Retry-After`; reintentá pasado ese tiempo.\n\n## Listados con API key\n\nCon una API key, los listados que llevan la línea «Con API key» devuelven la lista acotada. Las paginadas traen 25 elementos por defecto y 100 como máximo; las de página fija traen el tamaño fijo que dice su línea. Las demás listas no están acotadas en la v0, y esa línea no aparece en ellas. En las paginadas, pedir más, o un tamaño menor que 1 o no entero, responde `422`. El orden solo acepta las columnas que documenta cada operación, y la dirección `asc` o `desc`; otro valor responde `422`. Cada operación dice cómo se llaman sus parámetros de tamaño y de orden. Las estadísticas por período no son listas: con una API key exigen `start_date` y `end_date` (formato `AAAA-MM-DD`) y aceptan un rango de como máximo 366 días entre las dos (ambos incluidos); su línea «Con API key» lo dice. La retención por cohorte y los abandonos no están disponibles con una API key en la v0.\n\n## Versión v0\n\nLa v0 puede cambiar sin aviso, y algunas respuestas incluyen identificadores internos (por ejemplo `userId`).\n\n## Rutas que no aparecen\n\nSolo se listan las operaciones disponibles para API keys en esta versión. Si una ruta no está en esta documentación, no está disponible para API keys: llamarla con una key responde 403.\n\n## Especificación descargable\n\nLa especificación OpenAPI completa se descarga en `/docs/api.json`, para importarla en tu propia herramienta.\n\n## Webhooks\n\n### Cómo suscribirse\n\nCreá una suscripción con tu API key. Crear, editar, borrar, rotar el secreto y probar necesitan el permiso `communities:write` (o `communities:send`, que la incluye); listar y leer (suscripciones, entregas y eventos) necesitan `communities:read`, `communities:write` o `communities:send`. Recordá: en v0, `communities:write` solo administra suscripciones de webhooks. Una suscripción creada con una API key (o reapuntada a otra URL o reactivada con ella) queda ligada a esa key. Si revocás la key, la suscripción deja de recibir eventos: con el próximo evento de tu cuenta de un tipo al que esté suscrita pasa a `active: false` con `inactive_reason: \"key_revoked\"`, visible en `GET /api/v1/webhooks/{id}`. Las suscripciones creadas con la sesión no cambian. Una suscripción `key_revoked` no se puede reactivar: editarla con `active: true` responde `422`. Creá una suscripción nueva y revisá que la URL sea la tuya: si la key se filtró, pudo haberla cambiado. Suscripciones inactivas: `active: false` + `inactive_reason` (`key_revoked`), y reactivar una `key_revoked` responde 422 en todos los dominios. Lo mismo vale para una suscripción que ya estaba inactiva cuando se revocó la key: al intentar reactivarla pasa a `key_revoked`. Cada cuenta puede tener hasta **10 suscripciones activas**; la 11ª responde `409`. Una suscripción recibe los hechos que ocurren desde que está activa y suscrita a su tipo (o a `*`). No se pueden pedir hechos anteriores.\n\n- `GET /api/v1/webhooks`: lista tus suscripciones.\n- `POST /api/v1/webhooks`: crea una suscripción.\n- `GET /api/v1/webhooks/events`: lista todos los tipos de evento del dominio, con su estado (`live` o `planned`), si se pueden suscribir y un ejemplo (`null` en los `planned`).\n- `GET`, `PUT`, `DELETE /api/v1/webhooks/{webhook}`: lee, edita o elimina una suscripción.\n- `POST /api/v1/webhooks/{webhook}/rotate-secret`: genera un secreto nuevo (el anterior deja de firmar de inmediato).\n- `POST /api/v1/webhooks/{webhook}/test`: envía un evento de prueba.\n- `GET /api/v1/webhooks/{webhook}/deliveries`: historial de intentos de entrega.\n\n`events` acepta los tipos de la tabla de abajo o `\"*\"` para todos. La URL debe ser `https` y pública.\n\nPedido:\n\n```json\n{\n    \"url\": \"https://example.com/hooks/funnelchat\",\n    \"description\": \"Mi CRM\",\n    \"events\": [\n        \"group.created\",\n        \"group_participant.joined\"\n    ]\n}\n```\n\nRespuesta `201`. El campo `secret` se muestra **una sola vez** (también al rotarlo): guardalo.\n\n```json\n{\n    \"data\": {\n        \"uuid\": \"00000000-0000-4000-8000-0000000000a1\",\n        \"url\": \"https://example.com/hooks/funnelchat\",\n        \"description\": \"Mi CRM\",\n        \"events\": [\n            \"group.created\",\n            \"group_participant.joined\"\n        ],\n        \"active\": true,\n        \"inactive_reason\": null,\n        \"created_at\": \"2026-10-01T12:00:00Z\",\n        \"updated_at\": \"2026-10-01T12:00:00Z\",\n        \"secret\": \"whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n    }\n}\n```\n\n### Qué vas a recibir\n\nCada entrega es un `POST` con cuerpo JSON `{id, type, version, occurred_at, data}` y estos headers:\n\n| Header | Contenido |\n|---|---|\n| `Content-Type` | `application/json` |\n| `X-Funnelchat-Event` | El tipo del evento (igual al `type` del cuerpo). |\n| `X-Funnelchat-Delivery` | UUID del intento de entrega; cambia en cada reintento. |\n| `X-Funnelchat-Signature` | `t=<unix>,v1=<hex>`, la firma del cuerpo. |\n\n`id` identifica el evento y es estable entre reintentos; `occurred_at` es UTC; `version` es la versión del formato de `data`.\n\n### Verificar la firma\n\n`X-Funnelchat-Signature` es `t=<unix>,v1=<hex>`, donde `v1` es el HMAC-SHA256 en hexadecimal de `t + \".\" + cuerpo`. La clave es el secreto **completo** tal como se muestra, incluido el prefijo `whsec_` (no se decodifica nada). Comparalo en tiempo constante y rechazá entregas con un `t` de más de 5 minutos de diferencia.\n\n**Importante:** solo la firma está firmada. `X-Funnelchat-Event` y `X-Funnelchat-Delivery` no, así que tomá `type` e `id` del cuerpo ya verificado.\n\nPHP:\n\n```php\n<?php\n$secret = 'whsec_...'; // el secreto COMPLETO, con el prefijo whsec_\n$body = file_get_contents('php://input');\n$header = $_SERVER['HTTP_X_FUNNELCHAT_SIGNATURE'] ?? '';\n\nif (! preg_match('/^t=(\\d+),v1=([0-9a-f]{64})$/', $header, $m)) {\n    http_response_code(400);\n    exit;\n}\n[, $t, $signature] = $m;\n\n// Rechazá entregas viejas (protección contra repetición).\nif (abs(time() - (int) $t) > 300) {\n    http_response_code(400);\n    exit;\n}\n\n$expected = hash_hmac('sha256', $t.'.'.$body, $secret);\nif (! hash_equals($expected, $signature)) {\n    http_response_code(400);\n    exit;\n}\n\n$event = json_decode($body, true); // tomá type e id de ACÁ, no de los headers\n```\n\nJavaScript (Node.js):\n\n```javascript\nimport crypto from 'node:crypto';\nimport express from 'express';\n\nconst secret = 'whsec_...'; // el secreto COMPLETO, con el prefijo whsec_\nconst app = express();\n\n// Necesitás el cuerpo crudo: firmá sobre los bytes recibidos, no sobre JSON re-serializado.\napp.post('/hooks/funnelchat', express.raw({ type: 'application/json' }), (req, res) => {\n  const match = /^t=(\\d+),v1=([0-9a-f]{64})$/.exec(req.get('X-Funnelchat-Signature') ?? '');\n  if (!match) return res.sendStatus(400);\n  const [, t, signature] = match;\n\n  // Rechazá entregas viejas (protección contra repetición).\n  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.sendStatus(400);\n\n  const expected = crypto.createHmac('sha256', secret).update(`${t}.`).update(req.body).digest('hex');\n  const a = Buffer.from(expected);\n  const b = Buffer.from(signature);\n  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return res.sendStatus(400);\n\n  const event = JSON.parse(req.body.toString('utf8')); // tomá type e id de ACÁ, no de los headers\n  res.sendStatus(200);\n});\n```\n\n### Reintentos e idempotencia\n\n- Una entrega se considera exitosa si respondés **2xx dentro de 10 segundos**.\n- Hay hasta **4 intentos**, con esperas de **60 s, 300 s y 1800 s** entre ellos.\n- Se reintenta solo ante un error de red, un `5xx` o un `429`. Un `3xx` u otro `4xx` es definitivo y no se reintenta.\n- Las redirecciones nunca se siguen: configurá la URL final.\n- Es una entrega *al menos una vez*: podés recibir el mismo evento más de una vez. **Deduplicá por el `id` del cuerpo**; `X-Funnelchat-Delivery` cambia en cada intento.\n- El historial de intentos está en `GET /api/v1/webhooks/{webhook}/deliveries`.\n- La entrega puede estar desactivada en un entorno; en ese caso no se envía nada y la ruta de prueba responde `503`.\n\nEl campo `error` de cada intento fallido usa un vocabulario cerrado:\n\n| `error` | Significado |\n|---|---|\n| `HTTP <código>` | Tu servidor respondió con un estado que no es 2xx. |\n| `network error: timeout` | Tu servidor no respondió a tiempo. |\n| `network error: tls` | Falló la negociación TLS. |\n| `network error: connect_failed` | No se pudo conectar con tu servidor. |\n| `network error: other` | Otro error de red. |\n| `unsafe destination` | La URL resuelve a una dirección no pública; no se envió nada. |\n| `interrupted` | El intento se cortó antes de terminar. |\n| `deadline` | Se agotó el tiempo disponible antes de llegar a tu URL; no se envió nada y se reintenta. |\n| `secret unreadable` | No se pudo leer el secreto de la suscripción; rotalo con `rotate-secret`. |\n\n### Evento de prueba\n\n`POST /api/v1/webhooks/{webhook}/test` envía un único evento `webhook.test` a la URL de la suscripción, firmado igual que uno real y sin reintentos. Evento de prueba que se envía al pedir la prueba de una suscripción; no se puede suscribir a él.\n\nLa prueba espera la respuesta hasta **5 segundos** (en las entregas reales, 10 s) y se limita a **6 por minuto**. Responde `503` si la entrega está desactivada en el entorno y `409` si el secreto no se puede leer (rotalo con `rotate-secret`).\n\n```json\n{\n    \"id\": \"evt_0000000000000000000000000000000e\",\n    \"type\": \"webhook.test\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"subscription\": \"00000000-0000-4000-8000-00000000000c\",\n        \"sent_at\": \"2026-10-01T12:00:00Z\"\n    }\n}\n```\n\n### Tipos de evento\n\n| Tipo | Descripción | Estado | Suscribible |\n|---|---|---|---|\n| `group.created` | Se creó o se importó un grupo dentro de una campaña de la cuenta. | live | sí |\n| `group_participant.joined` | Una persona entró a un grupo de la cuenta; `campaign` es null si el grupo no es de una campaña. | live | sí |\n| `group_participant.left` | Una persona salió de un grupo de la cuenta; `campaign` es null si el grupo no es de una campaña. | live | sí |\n| `scheduled_message.finished` | Un envío programado terminó, con su resultado agregado. | live | sí |\n| `group.blocked` | Un grupo quedó inoperable: sin administrador conectado, con el link de invitación inválido o suspendido por WhatsApp. | live | sí |\n| `group.recovered` | Un grupo que estaba bloqueado volvió a operar. | live | sí |\n| `scheduled_message.group_delivery_failed` | Un envío programado falló en un grupo concreto, con el motivo desagregado. | live | sí |\n| `scheduled_message.response_received` | Alguien respondió a un envío programado votando una encuesta o respondiendo a un evento. | live | sí |\n| `campaign.status_changed` | Una campaña se activó o se pausó. | live | sí |\n| `pipeline.finished` | Terminó un pipeline de operaciones sobre grupos, con su resultado agregado y la clave de idempotencia del pedido que lo originó, cuando la hay. | live | sí |\n| `poll.voted` | Un participante votó en una encuesta enviada a un grupo, o cambió su voto. | live | sí |\n| `group.invite_link_renewed` | El enlace de invitación de un grupo cambió por una renovación, automática al detectarse inválido o pedida por el usuario; en v0 no se publican los cambios que detecta la sincronización ni el enlace inicial al crear el grupo. | live | sí |\n| `group.invite_link_down` | El enlace de invitación de un grupo quedó confirmado caído (WhatsApp respondió que no existe y la renovación no consiguió otro); no se publica por errores transitorios ni por grupos prohibidos o suspendidos, y se publica una sola vez por episodio de bloqueo. | live | sí |\n| `webhook.test` | Evento de prueba que se envía al pedir la prueba de una suscripción; no se puede suscribir a él. | live | no |\n\nLos tipos con estado `planned` todavía no se emiten y no se pueden suscribir: pedirlos en `events` responde `422`. `webhook.test` no se suscribe: llega solo al pedir la prueba de una suscripción.\n\n### Ejemplos\n\n#### `group.created`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000001\",\n    \"type\": \"group.created\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\",\n            \"type\": \"group\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\",\n            \"name\": \"Campaña de ejemplo\"\n        },\n        \"source\": \"created\"\n    }\n}\n```\n\n#### `group_participant.joined`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000002\",\n    \"type\": \"group_participant.joined\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\"\n        },\n        \"participant\": {\n            \"identity\": \"+5491100000000\",\n            \"identity_type\": \"phone\",\n            \"name\": \"Ana Pérez\"\n        }\n    }\n}\n```\n\n#### `group_participant.left`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000003\",\n    \"type\": \"group_participant.left\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\"\n        },\n        \"participant\": {\n            \"identity\": \"+5491100000000\",\n            \"identity_type\": \"phone\",\n            \"name\": \"Ana Pérez\"\n        }\n    }\n}\n```\n\n#### `scheduled_message.finished`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000004\",\n    \"type\": \"scheduled_message.finished\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"scheduled_message\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000004\",\n            \"name\": \"Envío de ejemplo\"\n        },\n        \"outcome\": \"partially_failed\",\n        \"groups\": {\n            \"total\": 10,\n            \"failed\": 1,\n            \"partially_failed\": 2\n        },\n        \"occurrence\": 1\n    }\n}\n```\n\n#### `group.blocked`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000005\",\n    \"type\": \"group.blocked\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\"\n        },\n        \"reason\": \"admin_access_lost\"\n    }\n}\n```\n\n#### `group.recovered`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000006\",\n    \"type\": \"group.recovered\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\"\n        },\n        \"reason\": \"access_restored\"\n    }\n}\n```\n\n#### `scheduled_message.group_delivery_failed`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000007\",\n    \"type\": \"scheduled_message.group_delivery_failed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"scheduled_message\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000007\"\n        },\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\"\n        },\n        \"reason\": \"device_disconnected\",\n        \"partial\": false,\n        \"occurrence\": 1\n    }\n}\n```\n\n#### `scheduled_message.response_received`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000008\",\n    \"type\": \"scheduled_message.response_received\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"scheduled_message\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000008\"\n        },\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\"\n        },\n        \"participant\": {\n            \"identity\": \"+5491100000000\",\n            \"identity_type\": \"phone\",\n            \"name\": \"Ana Pérez\"\n        },\n        \"response\": {\n            \"type\": \"poll\",\n            \"options\": [\n                \"Opción A\"\n            ],\n            \"rsvp\": null\n        }\n    }\n}\n```\n\n#### `campaign.status_changed`\n\n```json\n{\n    \"id\": \"evt_00000000000000000000000000000009\",\n    \"type\": \"campaign.status_changed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000009\",\n            \"name\": \"Campaña de ejemplo\"\n        },\n        \"from\": \"active\",\n        \"to\": \"paused\"\n    }\n}\n```\n\n#### `pipeline.finished`\n\n```json\n{\n    \"id\": \"evt_0000000000000000000000000000000a\",\n    \"type\": \"pipeline.finished\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-00000000000a\"\n        },\n        \"pipeline\": {\n            \"uuid\": \"00000000-0000-4000-8000-00000000000b\",\n            \"name\": \"Pipeline de ejemplo\"\n        },\n        \"outcome\": \"completed\",\n        \"actions\": {\n            \"total\": 5,\n            \"succeeded\": 4,\n            \"failed\": 0,\n            \"skipped\": 1,\n            \"cancelled\": 0\n        },\n        \"idempotency_key\": \"00000000-0000-4000-8000-00000000000d\"\n    }\n}\n```\n\n#### `poll.voted`\n\n```json\n{\n    \"id\": \"evt_0000000000000000000000000000000b\",\n    \"type\": \"poll.voted\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"poll\": {\n            \"uid\": \"3EB0000000000000000001\"\n        },\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\"\n        },\n        \"scheduled_message\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000004\"\n        },\n        \"participant\": {\n            \"identity\": \"+5491100000000\",\n            \"identity_type\": \"phone\",\n            \"name\": null\n        },\n        \"options\": [\n            \"Opción A\"\n        ]\n    }\n}\n```\n\n#### `group.invite_link_renewed`\n\n```json\n{\n    \"id\": \"evt_0000000000000000000000000000000c\",\n    \"type\": \"group.invite_link_renewed\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\",\n            \"type\": \"group\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\",\n            \"name\": \"Campaña de ejemplo\"\n        },\n        \"invite_link\": \"https://chat.whatsapp.com/EjemploNuevo0000000000001\",\n        \"previous_invite_link\": \"https://chat.whatsapp.com/EjemploAnterior000000000001\",\n        \"trigger\": \"automatic\",\n        \"recovered\": false\n    }\n}\n```\n\n#### `group.invite_link_down`\n\n```json\n{\n    \"id\": \"evt_0000000000000000000000000000000d\",\n    \"type\": \"group.invite_link_down\",\n    \"version\": 1,\n    \"occurred_at\": \"2026-10-01T12:00:00Z\",\n    \"data\": {\n        \"group\": {\n            \"uid\": \"120363000000000001@g.us\",\n            \"name\": \"Grupo de ejemplo\",\n            \"type\": \"group\"\n        },\n        \"campaign\": {\n            \"uuid\": \"00000000-0000-4000-8000-000000000001\",\n            \"name\": \"Campaña de ejemplo\"\n        },\n        \"reason\": \"http_404\",\n        \"renewal_attempted\": true\n    }\n}\n```\n\n### No confundir con los webhooks de campaña\n\nLas rutas `campaigns/{campaign}/webhooks` son un producto distinto (los webhooks legados de campaña), con otro formato, y **no reciben** estos eventos. Los eventos de esta sección se reciben solo a través de `/api/v1/webhooks`."}, "servers": [{"url": "https://api.funnelchat.com/api"}], "tags": [{"name": "Campañas"}, {"name": "Grupos de una campaña y operaciones"}, {"name": "Grupos"}, {"name": "Acciones de grupo"}, {"name": "Participantes"}, {"name": "Mensajes programados"}, {"name": "Respuestas y carpetas"}, {"name": "Estadísticas"}, {"name": "Webhooks de campaña (legado)"}, {"name": "Webhooks"}, {"name": "Utilidades"}], "security": [{"http": []}], "paths": {"/v1/campaigns": {"get": {"operationId": "campaign.index", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `created_at`, `id`, `name`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Lista las campañas de la cuenta", "tags": ["Campañas"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string"}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "Paginated set of `CampaignsResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/CampaignsResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}": {"get": {"operationId": "campaign.show", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Detalle de una campaña", "tags": ["Campañas"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "`CampaignResource`", "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/CampaignResource"}, {"type": "object", "required": ["moderation"]}]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/conditionals": {"get": {"operationId": "campaignConditional.index", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Condicionales de la campaña", "tags": ["Campañas"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "Array of `CampaignConditionalResource`", "content": {"application/json": {"schema": {"type": "array", "items": {"allOf": [{"$ref": "#/components/schemas/CampaignConditionalResource"}, {"type": "object", "required": ["redirect_group_name"]}]}}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/available-groups": {"get": {"operationId": "campaign.availableGroups", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `pageSize` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Grupos de la cuenta que se pueden sumar a la campaña", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "device_id", "in": "query", "required": true, "schema": {"type": "integer"}}, {"name": "type", "in": "query", "required": true, "schema": {"type": "string", "enum": ["groups", "ad-groups", "channels"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "pageSize", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 250}}, {"name": "name", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 255}}], "responses": {"200": {"description": "Array of `AvailableGroupResource`", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/AvailableGroupResource"}}, "meta": {"type": "string"}}, "required": ["data", "meta"]}, {"type": "string"}]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}}}, "/v1/campaigns/{campaign}/groups": {"get": {"operationId": "campaign.groups", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `id`, `name`, `created_at`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Grupos de la campaña", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string"}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}, {"name": "deviceId", "in": "query", "schema": {"type": "integer"}}, {"name": "status", "in": "query", "schema": {"type": "integer"}}, {"name": "origin", "in": "query", "schema": {"type": "integer", "enum": ["0", "1"]}}, {"name": "adminConnection", "in": "query", "schema": {"type": "integer", "enum": ["1", "2", "3"]}}, {"name": "adminPhone", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Paginated set of `GroupResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/GroupResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/campaigns/{campaign}/pipelines": {"get": {"operationId": "campaign.indexPipelines", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `per_page` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `id`, `name`, `group_index`, `created_at`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Pipelines de operaciones de la campaña", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["scheduled", "running", "completed", "failed", "cancelled"]}}, {"name": "action_type", "in": "query", "schema": {"type": "string", "enum": ["add", "new", "name", "description", "photo", "participants", "remove-participants", "administrators", "remove-administrators", "join_group", "members_can_send_messages", "remove_group"]}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["id", "name", "group_index", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"campaign": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}}, "required": ["id", "name"]}, "data": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "integer"}, "pipeline_id": {"type": "string"}, "name": {"type": ["string", "null"]}, "group_index": {"type": ["integer", "null"]}, "created_at": {"type": ["string", "null"]}, "summary": {"type": "object", "properties": {"total_actions": {"type": "integer", "minimum": 0}, "total_action_groups": {"type": "string"}, "status_counts": {"type": "object", "properties": {"scheduled": {"type": "string"}, "running": {"type": "string"}, "completed": {"type": "string"}, "failed": {"type": "string"}, "cancelled": {"type": "string"}, "pending_confirmation": {"type": "string"}, "skipped": {"type": "string"}}, "required": ["scheduled", "running", "completed", "failed", "cancelled", "pending_confirmation", "skipped"]}, "progress_percentage": {"type": "number"}}, "required": ["total_actions", "total_action_groups", "status_counts", "progress_percentage"]}}, "required": ["id", "pipeline_id", "name", "group_index", "created_at", "summary"]}}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "last_page": {"type": "integer"}, "per_page": {"type": "integer"}, "total": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "to": {"type": ["integer", "null"]}}, "required": ["current_page", "last_page", "per_page", "total", "from", "to"]}}, "required": ["campaign", "data", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/pipelines/{pipeline}": {"get": {"operationId": "campaign.showPipeline", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Detalle de un pipeline", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "pipeline", "in": "path", "required": true, "description": "The pipeline ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": ["object", "null"], "properties": {"pipeline_id": {"type": "string"}, "id": {"type": "integer"}, "campaign": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}}, "required": ["id", "name"]}, "summary": {"type": "object", "properties": {"name": {"type": ["string", "null"]}, "total_actions": {"type": "integer", "minimum": 0}, "total_action_groups": {"type": "string"}, "status_counts": {"type": "object", "properties": {"scheduled": {"type": "string"}, "running": {"type": "string"}, "completed": {"type": "string"}, "failed": {"type": "string"}, "cancelled": {"type": "string"}, "pending_confirmation": {"type": "string"}, "skipped": {"type": "string"}}, "required": ["scheduled", "running", "completed", "failed", "cancelled", "pending_confirmation", "skipped"]}, "progress_percentage": {"type": "number"}, "created_at": {"type": ["string", "null"]}, "scheduled_at": {"type": ["string", "null"]}, "completed_at": {"type": ["string", "null"]}}, "required": ["name", "total_actions", "total_action_groups", "status_counts", "progress_percentage", "created_at", "scheduled_at", "completed_at"]}, "actions": {"type": "array", "items": {"type": "string"}}}, "required": ["pipeline_id", "id", "campaign", "summary", "actions"]}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/operation-plans/config": {"get": {"operationId": "operationPlan.config", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Configuración disponible para planes", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"nudge_group_threshold": {"type": "integer"}, "default_daily_cap": {"type": "integer"}, "min_spacing_minutes": {"type": "integer"}, "confirmation_spacing_minutes": {"type": "integer"}, "default_window_start": {"type": "string"}, "default_window_end": {"type": "string"}, "daily_cap_max": {"type": "integer"}, "weekends_enabled": {"type": "boolean", "description": "Change `scheduled-bulk-admin-operations`, increment 8 (design.md\n§D10.2): lets the client show/hide the \"include weekends\" toggle."}}, "required": ["nudge_group_threshold", "default_daily_cap", "min_spacing_minutes", "confirmation_spacing_minutes", "default_window_start", "default_window_end", "daily_cap_max", "weekends_enabled"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/operation-plans": {"get": {"operationId": "operationPlan.index", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `per_page` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Planes de operación de la campaña", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"campaign": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}}, "required": ["id", "name"]}, "data": {"type": "array", "items": {"$ref": "#/components/schemas/OperationPlanSummaryResource"}}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "last_page": {"type": "integer"}, "per_page": {"type": "integer"}, "total": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "to": {"type": ["integer", "null"]}}, "required": ["current_page", "last_page", "per_page", "total", "from", "to"]}}, "required": ["campaign", "data", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}}}, "/v1/campaigns/{campaign}/operation-plans/{plan}": {"get": {"operationId": "operationPlan.show", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Detalle de un plan", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "plan", "in": "path", "required": true, "description": "The plan ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "`OperationPlanResource`", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OperationPlanResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/actions": {"get": {"operationId": "campaign.actions", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** página fija de 15 elementos; se recorre con `page`.", "summary": "Acciones de sesión ejecutadas para la campaña", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "Paginated set of `ActionResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ActionResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/campaigns/{campaign}/actions/{action}/groups": {"get": {"operationId": "groupManagement.actionGroup", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `name`, `status`, `created_at`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Grupos alcanzados por una acción", "tags": ["Grupos de una campaña y operaciones"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "action", "in": "path", "required": true, "description": "The action ID", "schema": {"type": "integer"}}, {"name": "name", "in": "query", "schema": {"type": "string", "maxLength": 255}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["name", "status", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "Paginated set of `ActionGroupResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ActionGroupResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/groups": {"get": {"operationId": "group.index", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `created_at`, `id`, `name`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Lista los grupos de la cuenta", "tags": ["Grupos"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string"}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string"}}, {"name": "type", "in": "query", "schema": {"type": "string", "enum": ["1", "2", "3", "4"]}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8"]}}, {"name": "deviceId", "in": "query", "schema": {"type": "integer"}}, {"name": "noCampaign", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "Paginated set of `GroupResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/GroupResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}, "cloud_api_groups_enabled": {"type": ["string", "boolean"]}}, "required": ["current_page", "from", "last_page", "links", "path", "per_page", "to", "total", "cloud_api_groups_enabled"]}}, "required": ["data", "links", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/devices/{device}/groups": {"get": {"operationId": "group.groups", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `pageSize` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Grupos que el número administra, según el proveedor", "tags": ["Grupos"], "parameters": [{"name": "device", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "pageSize", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 250}}, {"name": "name", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 255}}], "responses": {"200": {"description": "Array of `GroupMinResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/GroupMinResource"}}, "meta": {"type": "object", "properties": {"current_page": {}, "last_page": {}, "per_page": {}, "total": {"type": "integer"}}, "required": ["current_page", "last_page", "per_page", "total"]}}, "required": ["data", "meta"]}}}}, "400": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"error": {"anyOf": [{"type": "string"}, {"type": "string", "enum": ["An error has occurred"]}]}}, "required": ["error"]}, {"type": "object", "properties": {"error": {"type": "string", "const": "An error has occurred"}}, "required": ["error"]}]}}}}, "404": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "const": "Device not found"}}, "required": ["error"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/devices/{device}/ad-groups": {"get": {"operationId": "group.adGroups", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `pageSize` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Grupos de anuncios del número", "tags": ["Grupos"], "parameters": [{"name": "device", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "pageSize", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 250}}, {"name": "name", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 255}}], "responses": {"200": {"description": "Array of `GroupMinResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/GroupMinResource"}}, "meta": {"type": "object", "properties": {"current_page": {}, "last_page": {}, "per_page": {}, "total": {"type": "integer"}}, "required": ["current_page", "last_page", "per_page", "total"]}}, "required": ["data", "meta"]}}}}, "400": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"error": {"anyOf": [{"type": "string"}, {"type": "string", "enum": ["An error has occurred"]}]}}, "required": ["error"]}, {"type": "object", "properties": {"error": {"type": "string", "const": "An error has occurred"}}, "required": ["error"]}]}}}}, "404": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "const": "Device not found"}}, "required": ["error"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/devices/{device}/channels": {"get": {"operationId": "group.channels", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `pageSize` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Canales del número", "tags": ["Grupos"], "parameters": [{"name": "device", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "name", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 255}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "pageSize", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 250}}], "responses": {"200": {"description": "Array of `ChannelMinResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ChannelMinResource"}}, "meta": {"type": "object", "properties": {"current_page": {}, "last_page": {}, "per_page": {}, "total": {"type": "integer"}}, "required": ["current_page", "last_page", "per_page", "total"]}}, "required": ["data", "meta"]}}}}, "400": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"error": {"type": "string", "const": "Invalid response format from WAPI"}}, "required": ["error"]}, {"type": "object", "properties": {"error": {"anyOf": [{"type": "string"}, {"type": "string", "enum": ["An error has occurred"]}]}}, "required": ["error"]}, {"type": "object", "properties": {"error": {"type": "string", "const": "An error has occurred"}}, "required": ["error"]}]}}}}, "404": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"error": {"type": "string", "const": "Device not found"}}, "required": ["error"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/groups/{groupUid}/metadata": {"get": {"operationId": "groupMetadata.show", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Nombre, foto y descripción actuales en WhatsApp", "tags": ["Grupos"], "parameters": [{"name": "groupUid", "in": "path", "required": true, "description": "Plain string segment — not a model binding.", "schema": {"type": "string"}}, {"name": "device_id", "in": "query", "required": true, "schema": {"type": "integer", "minimum": 1}}, {"name": "group_uid", "in": "query", "required": true, "schema": {"type": "string", "pattern": "^[0-9]{10,25}(-[0-9]+)?(@g\\.us|@newsletter)?$"}}, {"name": "type", "in": "query", "schema": {"type": "string", "enum": ["groups", "ad-groups", "channels"]}}], "responses": {"200": {"description": "`GroupMetadataResource`\n\n`ChannelMetadataResource`", "content": {"application/json": {"schema": {"anyOf": [{"$ref": "#/components/schemas/GroupMetadataResource"}, {"$ref": "#/components/schemas/ChannelMetadataResource"}]}}}}, "502": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "const": "Gateway error. Please try again later."}}, "required": ["message"]}}}}, "404": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"message": {"type": "string", "const": "Group not found or not accessible."}}, "required": ["message"]}, {"type": "object", "properties": {"message": {"type": "string", "const": "Device not found or access denied."}}, "required": ["message"]}]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/groups/{group}": {"get": {"operationId": "group.show", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Detalle de un grupo", "tags": ["Grupos"], "parameters": [{"name": "group", "in": "path", "required": true, "description": "The group uid", "schema": {"type": "string"}}], "responses": {"200": {"description": "`GroupResource`", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GroupResource"}}}}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/groups/{group}/actions": {"get": {"operationId": "group.actions", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `status`, `created_at`, `updated_at`, `completed_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Acciones de sesión sobre el grupo", "tags": ["Grupos"], "parameters": [{"name": "group", "in": "path", "required": true, "description": "The group uid", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["status", "created_at", "updated_at", "completed_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "Paginated set of `ActionGroupResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ActionGroupResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/groups/{group}/messages": {"get": {"operationId": "group.messages", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** página fija de 3 elementos; se recorre con `page`.", "summary": "Mensajes enviados al grupo", "tags": ["Grupos"], "parameters": [{"name": "group", "in": "path", "required": true, "description": "The group uid", "schema": {"type": "string"}}], "responses": {"200": {"description": "Paginated set of `MessageResource`", "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": {"current_page": {"type": "integer", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/groups/{group}/scheduled-messages": {"get": {"operationId": "group.scheduledMessages", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `send_at`, `name`, `status`, `id`, `created_at`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Envíos programados que incluyen al grupo", "tags": ["Grupos"], "parameters": [{"name": "group", "in": "path", "required": true, "description": "The group uid", "schema": {"type": "string"}}, {"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["send_at", "name", "status", "id", "created_at", "updated_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["ASC", "DESC"]}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "Paginated set of `ScheduledMessageResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ScheduledMessageResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/campaigns/{campaign}/participants": {"get": {"operationId": "campaign.participants", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `updated_at`, `id`, `created_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Participantes de la campaña", "tags": ["Participantes"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "phone", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "orderBy", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": ["string", "null"], "enum": ["asc", "desc", null]}}, {"name": "perPage", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}], "responses": {"200": {"description": "Paginated set of `ParticipantResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ParticipantResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/campaigns/{campaign}/campaign-participants": {"get": {"operationId": "campaign.campaignParticipants", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `joined_at`, `left_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Participantes con su grupo actual", "tags": ["Participantes"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "search", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "status", "in": "query", "schema": {"type": ["string", "null"], "enum": ["active", "exited", null]}}, {"name": "orderBy", "in": "query", "schema": {"type": ["string", "null"], "enum": ["joined_at", "left_at", null]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": ["string", "null"], "enum": ["asc", "desc", "ASC", "DESC", null]}}, {"name": "perPage", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "start_date", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "timezone", "in": "query", "schema": {"type": ["string", "null"]}}, {"name": "date_rule", "in": "query", "schema": {"type": ["integer", "null"], "enum": ["1", "2", "3", null]}}, {"name": "selection_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "none", null]}}, {"name": "groups_uids[]", "in": "query", "schema": {"type": "array", "items": {"type": "string"}}}], "responses": {"200": {"description": "Paginated set of `CampaignParticipantResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/CampaignParticipantResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/campaigns/{campaign}/participant-events": {"get": {"operationId": "campaign.participantEvents", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Entradas y salidas en toda la campaña", "tags": ["Participantes"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "search", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 50}}, {"name": "event_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "join", "leave", null]}}, {"name": "page", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1, "maximum": 100}}, {"name": "start_date", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "timezone", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 64}}, {"name": "date_mode", "in": "query", "schema": {"type": ["string", "null"], "enum": ["both", "joins_only", "leaves_only", null]}}, {"name": "selection_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "none", null]}}, {"name": "groups_uids[]", "in": "query", "schema": {"type": "array", "items": {"type": "string", "maxLength": 50}}}, {"name": "participant_filter", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "active", null]}}], "responses": {"200": {"description": "Paginated set of `ParticipantEventResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ParticipantEventResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/groups/participants": {"get": {"operationId": "group.participants", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `created_at`, `id`, `updated_at`; dirección `orderDirection`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Participantes de un grupo", "tags": ["Participantes"], "parameters": [{"name": "groupUid", "in": "query", "required": true, "schema": {"type": "string"}}, {"name": "phone", "in": "query", "schema": {"type": "string"}}, {"name": "isAdmin", "in": "query", "schema": {"type": "string", "enum": ["true", "false", "1", "0"]}}, {"name": "eligibleForAdmin", "in": "query", "schema": {"type": "string", "enum": ["true", "false", "1", "0"]}}, {"name": "orderBy", "in": "query", "schema": {"type": "string"}}, {"name": "orderDirection", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "Paginated set of `ParticipantResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ParticipantResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/groups/{group}/participant-events": {"get": {"operationId": "group.participantEvents", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Entradas y salidas de un grupo", "tags": ["Participantes"], "parameters": [{"name": "group", "in": "path", "required": true, "description": "The group uid", "schema": {"type": "string"}}, {"name": "search", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 50}}, {"name": "event_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "join", "leave", null]}}, {"name": "page", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": ["integer", "null"], "minimum": 1, "maximum": 100}}, {"name": "start_date", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": ["string", "null"], "format": "date-time"}}, {"name": "timezone", "in": "query", "schema": {"type": ["string", "null"], "maxLength": 64}}, {"name": "date_mode", "in": "query", "schema": {"type": ["string", "null"], "enum": ["both", "joins_only", "leaves_only", null]}}, {"name": "selection_type", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "none", null]}}, {"name": "groups_uids[]", "in": "query", "schema": {"type": "array", "items": {"type": "string", "maxLength": 50}}}, {"name": "participant_filter", "in": "query", "schema": {"type": ["string", "null"], "enum": ["all", "active", null]}}], "responses": {"200": {"description": "Paginated set of `ParticipantEventResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ParticipantEventResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/scheduled-messages": {"get": {"operationId": "scheduledMessage.index", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `created_at`, `id`, `name`, `updated_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Lista los envíos programados", "tags": ["Mensajes programados"], "parameters": [{"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string"}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["0", "1", "2", "3", "4", "5", "6", "7", "8"]}}, {"name": "only_needs_connection", "in": "query", "description": "The `boolean` rule only accepts PHP-native booleans/0/1/\"0\"/\"1\" — a\nquery-string boolean travels as the literal string \"true\"/\"false\" and\nwas rejected with a 422 before ever reaching the filter_var() coercion\nbelow. Whitelist the common wire forms explicitly instead.", "schema": {"type": "string", "enum": ["true", "false", "1", "0"]}}, {"name": "folder_id", "in": "query", "schema": {"type": ["integer", "null"]}}, {"name": "unclassified", "in": "query", "schema": {"type": "string", "enum": ["true", "false", "1", "0"]}}], "responses": {"200": {"description": "Paginated set of `ScheduledMessageIndexResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ScheduledMessageIndexResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/scheduled-messages/{scheduledMessage}": {"get": {"operationId": "scheduledMessage.show", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Detalle de un envío", "tags": ["Mensajes programados"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "`App.Modules.ScheduledMessages.Resources.ScheduledMessageResource`", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/App.Modules.ScheduledMessages.Resources.ScheduledMessageResource"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/scheduled-messages/{scheduledMessage}/groups": {"get": {"operationId": "scheduledMessage.groups", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** página fija de 3 elementos; se recorre con `page`. Orden: `orderBy` acepta `created_at`, `id`, `name`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Grupos destino del envío", "tags": ["Mensajes programados"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}, {"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string"}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer"}}, {"name": "status", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/LengthAwarePaginator"}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/scheduled-messages/{scheduledMessage}/group-messages": {"get": {"operationId": "scheduledMessage.groupMessages", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`). Orden: `orderBy` acepta `group_message_template.id`, `group_message_template.status`, `groups.name`, `group_message_template.created_at`; dirección `orderByMethod`: `asc` o `desc`. Otro valor responde `422`.", "summary": "Resultado por grupo", "tags": ["Mensajes programados"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}, {"name": "name", "in": "query", "schema": {"type": "string"}}, {"name": "orderBy", "in": "query", "schema": {"type": "string", "enum": ["group_message_template.id", "group_message_template.status", "groups.name", "group_message_template.created_at"]}}, {"name": "orderByMethod", "in": "query", "schema": {"type": "string", "enum": ["asc", "desc"]}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "status", "in": "query", "schema": {"type": "integer"}}, {"name": "edit_status", "in": "query", "description": "Outcome of the latest edit of the sent text (edit-sent), kept\napart from `status`, which stays the delivery state.\n| |\n|---|\n| `1` <br/> Confirmed delivered, inside the window: the provider accepted the edit. |\n| `2` <br/> Confirmed delivered, but 15 minutes had already passed since it was sent to that group. |\n| `3` <br/> Cloud API device, a channel, or a provider that cannot edit. |\n| `4` <br/> The provider returned an error, or the message never reached the group. |", "schema": {"$ref": "#/components/schemas/ScheduledMessageEditStatusEnum"}}, {"name": "run", "in": "query", "description": "Optional occurrence filter (D3): local calendar date (Y-m-d) of a run,\nresolved into a UTC window by ScheduledMessageRunService. Additive —\nomitting it preserves the exact previous behaviour (MAX(id) globally).", "schema": {"type": "string", "format": "date"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"template_id": {"type": "string"}, "group_id": {"type": "string"}, "group_name": {"type": "string"}, "campaign_name": {"type": "string"}, "audience": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "schedule_message_status": {"type": "string"}, "error_info": {}, "totaL_readed": {}, "total_played": {}, "reactions_count": {}, "clicks": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "sent_by": {"type": "array", "items": {"type": "string"}}, "attempts": {"type": "integer"}, "last_attempt_at": {"type": "string"}, "edit_status": {"type": ["string", "null"], "description": "Latest edit of the sent text (ScheduledMessageEditStatusEnum)\nand its reason code; the provider's raw answer stays in\n`message_deliveries` for support and never reaches the response."}, "edit_reason": {"type": ["string", "null"]}}, "required": ["template_id", "group_id", "group_name", "campaign_name", "audience", "schedule_message_status", "error_info", "totaL_readed", "total_played", "reactions_count", "clicks", "sent_by", "attempts", "last_attempt_at", "edit_status", "edit_reason"]}}, "links": {"type": "object", "properties": {"first": {"type": "string"}, "last": {"type": "string"}, "prev": {"type": ["string", "null"]}, "next": {"type": "string"}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer"}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "string"}, "per_page": {"type": "integer"}, "to": {"type": ["integer", "null"]}, "total": {"type": "string"}}, "required": ["current_page", "from", "last_page", "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"}}}}, "/v1/scheduled-messages/{scheduledMessage}/readed-played-rates": {"get": {"operationId": "scheduledMessage.readedAndPlayedRates", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Tasas de lectura y reproducción", "tags": ["Mensajes programados"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}, {"name": "run", "in": "query", "schema": {"type": "string", "format": "date"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"audience": {"type": ["integer", "null"]}, "total_readed": {"type": ["integer", "null"]}, "total_played": {"type": ["integer", "null"]}}, "required": ["audience", "total_readed", "total_played"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/scheduled-messages/{scheduledMessage}/runs": {"get": {"operationId": "scheduledMessage.runs", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Ocurrencias ejecutadas de un envío recurrente", "tags": ["Mensajes programados"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}], "responses": {"200": {"description": "Array of `ScheduledMessageRunsResource`", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/ScheduledMessageRunsResource"}}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "422": {"$ref": "#/components/responses/ValidationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/scheduled-messages/folders": {"get": {"operationId": "scheduledMessageFolder.index", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Carpetas de envíos", "tags": ["Respuestas y carpetas"], "responses": {"200": {"description": "Array of `ScheduledMessageFolderResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/ScheduledMessageFolderResource"}}, "meta": {"type": "object", "properties": {"all_count": {"type": "integer", "minimum": 0}, "unclassified_count": {"type": "integer", "minimum": 0}}, "required": ["all_count", "unclassified_count"]}}, "required": ["data", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/scheduled-messages/{scheduledMessage}/responses": {"get": {"operationId": "scheduledMessage.responses", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Respuestas recibidas a un envío", "tags": ["Respuestas y carpetas"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}, {"name": "page", "in": "query", "description": "Coordinator finding (LOW): an unbounded `page` combined with\n`perPage` lets `($page-1)*$perPage` grow arbitrarily, which\n`MessageResponseReader::paginate()`'s out-of-range\nshort-circuit already makes cheap (no SELECT runs), but the\ncap here still guards against a pathological/overflowing\noffset value reaching that arithmetic at all. 100,000 is\ngenerous headroom above the measured production worst case\n(39,002 rows for a single poll/event, i.e. ≤39,002 pages even\nat perPage=1).", "schema": {"type": "integer", "minimum": 1, "maximum": 100000}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 1000}}, {"name": "type", "in": "query", "schema": {"type": "string", "enum": ["poll", "event"]}}], "responses": {"200": {"description": "Array of `MessageResponseResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/MessageResponseResource"}}, "meta": {"type": "object", "properties": {"total": {"type": "string"}, "per_page": {"type": "integer"}, "current_page": {"type": "integer"}, "last_page": {"type": "integer"}}, "required": ["total", "per_page", "current_page", "last_page"]}}, "required": ["data", "meta"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}}}, "/v1/scheduled-messages/{scheduledMessage}/response-tags": {"get": {"operationId": "scheduledMessage.responseTags", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Etiquetas que se aplican a quien responde", "tags": ["Respuestas y carpetas"], "parameters": [{"name": "scheduledMessage", "in": "path", "required": true, "description": "The scheduled message ID", "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"message_template_id": {"type": "string"}, "block_type": {"type": "string"}, "options": {"type": "string"}, "responses_total": {"type": "string"}, "untagged_total": {"type": "string"}}, "required": ["message_template_id", "block_type", "options", "responses_total", "untagged_total"]}}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/stats/participants": {"get": {"operationId": "stats.participantStats", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** `start_date` y `end_date` son obligatorios, con formato `AAAA-MM-DD`, y el rango entre los dos, ambos incluidos, admite como máximo 366 días (un año completo, bisiesto incluido). Si falta una de las dos fechas, si una es inválida, si `end_date` es anterior a `start_date` o si el rango es mayor, responde `422`.", "summary": "Participantes por período", "tags": ["Estadísticas"], "parameters": [{"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "unit", "in": "query", "schema": {"type": "string", "enum": ["day", "month", "hour"]}}, {"name": "type", "in": "query", "schema": {"type": "string", "enum": ["in", "out"]}}, {"name": "target", "in": "query", "schema": {"type": "string", "enum": ["groups", "campaigns"]}}, {"name": "ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "fill_missing", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"in": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "total_participants": {"type": "string"}}, "required": ["data", "total_participants"]}, "out": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "total_participants": {"type": "string"}}, "required": ["data", "total_participants"]}}, "required": ["in", "out"]}, {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "total_participants": {"type": "string"}}, "required": ["data", "total_participants"]}, {"type": "object", "properties": {"in": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_participants": {"type": "integer", "const": 0}}, "required": ["data", "total_participants"]}, "out": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_participants": {"type": "integer", "const": 0}}, "required": ["data", "total_participants"]}}, "required": ["in", "out"]}, {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_participants": {"type": "integer", "const": 0}}, "required": ["data", "total_participants"]}]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/stats/active-participants": {"get": {"operationId": "stats.activeParticipants", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** `start_date` y `end_date` son obligatorios, con formato `AAAA-MM-DD`, y el rango entre los dos, ambos incluidos, admite como máximo 366 días (un año completo, bisiesto incluido). Si falta una de las dos fechas, si una es inválida, si `end_date` es anterior a `start_date` o si el rango es mayor, responde `422`.", "summary": "Participantes activos", "tags": ["Estadísticas"], "parameters": [{"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "unit", "in": "query", "schema": {"type": "string", "enum": ["day", "month", "hour"]}}, {"name": "target", "in": "query", "schema": {"type": "string", "enum": ["groups", "campaigns"]}}, {"name": "ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "status", "in": "query", "schema": {"type": "string", "enum": ["active", "inactive"]}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"active": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"date": {"type": "string"}, "count": {"type": "integer"}}, "required": ["date", "count"]}}, "total_participants": {"type": "string"}}, "required": ["data", "total_participants"]}, "inactive": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"date": {"type": "string"}, "count": {"type": "integer"}}, "required": ["date", "count"]}}, "total_participants": {"type": "string"}}, "required": ["data", "total_participants"]}}, "required": ["active", "inactive"]}, {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"date": {"type": "string"}, "count": {"type": "integer"}}, "required": ["date", "count"]}}, "total_participants": {"type": "string"}}, "required": ["data", "total_participants"]}, {"type": "object", "properties": {"active": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_participants": {"type": "integer", "const": 0}}, "required": ["data", "total_participants"]}, "inactive": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_participants": {"type": "integer", "const": 0}}, "required": ["data", "total_participants"]}}, "required": ["active", "inactive"]}, {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_participants": {"type": "integer", "const": 0}}, "required": ["data", "total_participants"]}]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/stats/groups": {"get": {"operationId": "stats.groupStats", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** `start_date` y `end_date` son obligatorios, con formato `AAAA-MM-DD`, y el rango entre los dos, ambos incluidos, admite como máximo 366 días (un año completo, bisiesto incluido). Si falta una de las dos fechas, si una es inválida, si `end_date` es anterior a `start_date` o si el rango es mayor, responde `422`.", "summary": "Grupos por estado", "tags": ["Estadísticas"], "parameters": [{"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "unit", "in": "query", "required": true, "schema": {"type": "string", "enum": ["day", "month", "hour"]}}, {"name": "fill_missing", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "total_groups": {"type": "string"}}, "required": ["data", "total_groups"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/stats/clicks": {"get": {"operationId": "stats.clickStats", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** `start_date` y `end_date` son obligatorios, con formato `AAAA-MM-DD`, y el rango entre los dos, ambos incluidos, admite como máximo 366 días (un año completo, bisiesto incluido). Si falta una de las dos fechas, si una es inválida, si `end_date` es anterior a `start_date` o si el rango es mayor, responde `422`.", "summary": "Clics en links", "tags": ["Estadísticas"], "parameters": [{"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "unit", "in": "query", "schema": {"type": "string", "enum": ["day", "month", "hour"]}}, {"name": "target", "in": "query", "schema": {"type": "string", "enum": ["groups", "campaigns"]}}, {"name": "ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "fill_missing", "in": "query", "schema": {"type": "boolean"}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}}, "total_clicks": {"type": "string"}}, "required": ["data", "total_clicks"]}, {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total_clicks": {"type": "integer", "const": 0}}, "required": ["data", "total_clicks"]}]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/stats/records": {"get": {"operationId": "stats.statsRecords", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `per_page` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Registros", "tags": ["Estadísticas"], "parameters": [{"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "target", "in": "query", "schema": {"type": "string", "enum": ["groups", "campaigns"]}}, {"name": "ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "devices[]", "in": "query", "schema": {"type": "array", "items": {"type": "string", "maxLength": 64}}}, {"name": "countries[]", "in": "query", "schema": {"type": "array", "items": {"type": "string", "maxLength": 10}}}, {"name": "search", "in": "query", "schema": {"type": "string", "maxLength": 255}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"anyOf": [{"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "string"}, "address": {"type": "string"}, "browser": {"type": "string"}, "country": {"type": "string"}, "device": {"type": "string"}, "language": {"type": "string"}, "platform": {"type": "string"}, "referrer": {"type": "string"}, "group": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}}, "required": ["id", "name"]}, "phone": {"type": "string"}, "email": {"type": "string"}, "name": {"type": "string"}, "metadata": {}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}}, "required": ["id", "address", "browser", "country", "device", "language", "platform", "referrer", "group", "phone", "email", "name", "metadata", "created_at", "updated_at"]}}, "total": {"type": "integer", "minimum": 0}, "per_page": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [50]}]}, "current_page": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [1]}]}, "last_page": {"type": "number"}}, "required": ["data", "total", "per_page", "current_page", "last_page"]}, {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "total": {"type": "integer", "const": 0}, "per_page": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [50]}]}, "current_page": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [1]}]}}, "required": ["data", "total", "per_page", "current_page"]}]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/stats/country-metrics": {"get": {"operationId": "stats.countryMetrics", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Métricas por país", "tags": ["Estadísticas"], "parameters": [{"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "target", "in": "query", "schema": {"type": "string", "enum": ["groups", "campaigns"]}}, {"name": "ids[]", "in": "query", "schema": {"type": "array", "items": {"type": "integer"}}}, {"name": "countries[]", "in": "query", "schema": {"type": "array", "items": {"type": "string", "maxLength": 10}}}], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"anyOf": [{"type": "object", "properties": {"summary": {"type": "object", "properties": {"total_contacts": {"type": "string"}, "total_countries": {"type": "integer", "minimum": 0}, "total_clicks": {"type": "string"}, "total_entries": {"type": "string"}, "total_exits": {"type": "string"}}, "required": ["total_contacts", "total_countries", "total_clicks", "total_entries", "total_exits"]}, "countries": {"type": "array", "items": {"type": "object", "properties": {"country_code": {"type": "string"}, "country_name": {"type": "string"}, "contacts": {"type": "integer"}, "percentage": {"type": "number"}, "clicks": {"type": "integer"}, "entries": {"type": "integer"}, "entry_rate": {"type": "number"}, "exits": {"type": "integer"}}, "required": ["country_code", "country_name", "contacts", "percentage", "clicks", "entries", "entry_rate", "exits"]}}}, "required": ["summary", "countries"]}, {"type": "object", "properties": {"summary": {"type": "object", "properties": {"total_contacts": {"type": "integer", "const": 0}, "total_countries": {"type": "integer", "const": 0}, "total_clicks": {"type": "integer", "const": 0}, "total_entries": {"type": "integer", "const": 0}, "total_exits": {"type": "integer", "const": 0}}, "required": ["total_contacts", "total_countries", "total_clicks", "total_entries", "total_exits"]}, "countries": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}}, "required": ["summary", "countries"]}]}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}}}, "/v1/stats/countries": {"get": {"operationId": "stats.countryList", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Países presentes", "tags": ["Estadísticas"], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"type": "object", "properties": {"country_code": {"type": ["string", "null"]}, "country_name": {"type": ["string", "null"]}}, "required": ["country_code", "country_name"]}}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/webhooks": {"get": {"operationId": "campaignWebhook.index", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Nota:** Webhooks legados de campaña, con otro formato; no reciben los eventos de plataforma (ver `/webhooks`).", "summary": "Webhooks configurados en la campaña", "tags": ["Webhooks de campaña (legado)"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}], "responses": {"200": {"description": "Array of `CampaignWebhookResource`", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/CampaignWebhookResource"}}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/campaigns/{campaign}/webhooks/logs": {"get": {"operationId": "campaignWebhook.logs", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `per_page` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`).", "summary": "Entregas de esos webhooks", "tags": ["Webhooks de campaña (legado)"], "parameters": [{"name": "campaign", "in": "path", "required": true, "description": "The campaign ID", "schema": {"type": "integer"}}, {"name": "start_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "end_date", "in": "query", "schema": {"type": "string", "format": "date-time"}}, {"name": "status", "in": "query", "schema": {"type": "integer", "enum": ["0", "1", "2"]}}, {"name": "type", "in": "query", "schema": {"type": "integer", "enum": ["0", "1", "2"]}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "Paginated set of `CampaignWebhookLogResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/CampaignWebhookLogResource"}}, "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", "minimum": 1}, "from": {"type": ["integer", "null"], "minimum": 1}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "description": "Generated paginator links.", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": ["string", "null"], "description": "Base path for paginator generated URLs."}, "per_page": {"type": "integer", "description": "Number of items shown per page.", "minimum": 0}, "to": {"type": ["integer", "null"], "description": "Number of the last item in the slice.", "minimum": 1}, "total": {"type": "integer", "description": "Total number of items being paginated.", "minimum": 0}}, "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"}}}}, "/v1/webhooks": {"get": {"operationId": "webhookSubscription.index", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `per_page` o `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`; mandar los dos con valores distintos también responde `422`).", "summary": "Lista las suscripciones de la cuenta", "tags": ["Webhooks"], "parameters": [{"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "Paginated set of `WebhookSubscriptionResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookSubscriptionResource"}}, "links": {"type": "object", "properties": {"first": {"type": "string"}, "last": {"type": "string"}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer", "minimum": 1}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "page": {"type": ["integer", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer", "minimum": 1}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer", "minimum": 0}}, "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"}}}, "post": {"operationId": "webhookSubscription.store", "description": "**Permiso requerido:** `communities:write` (Escribir)\n\n**Nota:** Hasta 10 activas por cuenta; la URL tiene que ser `https` y pública.", "summary": "Crea una suscripción", "tags": ["Webhooks"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StoreWebhookSubscriptionRequest"}}}}, "responses": {"201": {"description": "Suscripción creada. `secret` solo viene en esta respuesta.", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookSubscriptionWithSecret"}}, "required": ["data"]}}}}, "409": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}, "422": {"$ref": "#/components/responses/ValidationException"}}}}, "/v1/webhooks/events": {"get": {"operationId": "webhookSubscription.events", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Catálogo de eventos con un ejemplo de cada uno", "tags": ["Webhooks"], "responses": {"200": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"anyOf": [{"type": "object", "properties": {"type": {"type": "string"}, "description": {"type": "string"}, "status": {"type": "string", "const": "live"}, "subscribable": {"type": "boolean"}, "example": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string"}, "version": {"type": "integer", "const": 1}, "occurred_at": {"type": "string"}, "data": {"anyOf": [{"type": "object", "properties": {"subscription": {}, "sent_at": {"type": "string"}}, "required": ["subscription", "sent_at"]}, {"type": "object", "additionalProperties": {}}]}}, "required": ["id", "type", "version", "occurred_at", "data"]}}, "required": ["type", "description", "status", "subscribable", "example"]}, {"type": "object", "properties": {"type": {"type": "string"}, "description": {"type": "string"}, "status": {"type": "string", "const": "planned"}, "subscribable": {"type": "boolean"}, "example": {"type": "null"}}, "required": ["type", "description", "status", "subscribable", "example"]}]}}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/webhooks/{webhook}": {"get": {"operationId": "webhookSubscription.show", "description": "**Permiso requerido:** `communities:read` (Leer)", "summary": "Detalle de una suscripción", "tags": ["Webhooks"], "parameters": [{"name": "webhook", "in": "path", "required": true, "description": "The webhook UUID", "schema": {"type": "string"}}], "responses": {"200": {"description": "`WebhookSubscriptionResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookSubscriptionResource"}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}, "put": {"operationId": "webhookSubscription.update", "description": "**Permiso requerido:** `communities:write` (Escribir)", "summary": "Edita una suscripción", "tags": ["Webhooks"], "parameters": [{"name": "webhook", "in": "path", "required": true, "description": "The webhook UUID", "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateWebhookSubscriptionRequest"}}}}, "responses": {"200": {"description": "`WebhookSubscriptionResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookSubscriptionResource"}}, "required": ["data"]}}}}, "422": {"$ref": "#/components/responses/ValidationException"}, "409": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}, "delete": {"operationId": "webhookSubscription.destroy", "description": "**Permiso requerido:** `communities:write` (Escribir)", "summary": "Borra una suscripción", "tags": ["Webhooks"], "parameters": [{"name": "webhook", "in": "path", "required": true, "description": "The webhook UUID", "schema": {"type": "string"}}], "responses": {"204": {"description": "No content"}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/webhooks/{webhook}/rotate-secret": {"post": {"operationId": "webhookSubscription.rotateSecret", "description": "**Permiso requerido:** `communities:write` (Escribir)", "summary": "Genera un secreto de firma nuevo", "tags": ["Webhooks"], "parameters": [{"name": "webhook", "in": "path", "required": true, "description": "The webhook UUID", "schema": {"type": "string"}}], "responses": {"200": {"description": "Secreto nuevo; el anterior deja de firmar. `secret` solo viene en esta respuesta.", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookSubscriptionWithSecret"}}, "required": ["data"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/webhooks/{webhook}/test": {"post": {"operationId": "webhookSubscription.test", "description": "**Permiso requerido:** `communities:write` (Escribir)\n\n**Nota:** Envía una petición real a la URL; 6 por minuto.", "summary": "Envía un evento de prueba firmado", "tags": ["Webhooks"], "parameters": [{"name": "webhook", "in": "path", "required": true, "description": "The webhook UUID", "schema": {"type": "string"}}], "responses": {"200": {"description": "`WebhookDeliveryResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/WebhookDeliveryResource"}}, "required": ["data"]}}}}, "409": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "503": {"description": "", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string"}}, "required": ["message"]}}}}, "403": {"$ref": "#/components/responses/AuthorizationException"}, "404": {"$ref": "#/components/responses/ModelNotFoundException"}, "401": {"$ref": "#/components/responses/AuthenticationException"}}}}, "/v1/webhooks/{webhook}/deliveries": {"get": {"operationId": "webhookSubscription.deliveries", "description": "**Permiso requerido:** `communities:read` (Leer)\n\n**Con API key:** la respuesta siempre viene paginada. Tamaño de página: `per_page` o `perPage` (por defecto 25, máximo 100; un valor mayor, menor que 1 o no entero responde `422`; mandar los dos con valores distintos también responde `422`).", "summary": "Historial de entregas de una suscripción", "tags": ["Webhooks"], "parameters": [{"name": "webhook", "in": "path", "required": true, "description": "The webhook UUID", "schema": {"type": "string"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 10000}}, {"name": "perPage", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "Paginated set of `WebhookDeliveryResource`", "content": {"application/json": {"schema": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/WebhookDeliveryResource"}}, "links": {"type": "object", "properties": {"first": {"type": "string"}, "last": {"type": "string"}, "prev": {"type": ["string", "null"]}, "next": {"type": ["string", "null"]}}, "required": ["first", "last", "prev", "next"]}, "meta": {"type": "object", "properties": {"current_page": {"type": "integer", "minimum": 1}, "from": {"type": ["integer", "null"]}, "last_page": {"type": "integer", "minimum": 1}, "links": {"type": "array", "items": {"type": "object", "properties": {"url": {"type": ["string", "null"]}, "page": {"type": ["integer", "null"]}, "label": {"type": "string"}, "active": {"type": "boolean"}}, "required": ["url", "label", "active"]}}, "path": {"type": "string"}, "per_page": {"type": "integer", "minimum": 1}, "to": {"type": ["integer", "null"]}, "total": {"type": "integer", "minimum": 0}}, "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"}}}}}, "components": {"securitySchemes": {"http": {"type": "http", "description": "Tu API key de Funnelchat, enviada en cada llamada como `Authorization: Bearer <id>|fc_live_...`.", "scheme": "bearer"}}, "schemas": {"ActionGroupResource": {"anyOf": [{"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "status": {"type": "string"}, "info": {}, "action_name": {"type": "string"}, "action_label": {"type": ["string", "null"]}, "executed_at": {"type": ["string", "null"]}, "executed_by": {"type": ["string", "null"]}, "groups": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}}, "required": ["id", "name", "status", "info", "action_name", "action_label", "executed_at", "executed_by", "groups"]}, {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": ["string", "null"]}, "status": {"type": "string"}, "info": {}, "action_name": {"type": ["string", "null"]}, "action_label": {"type": ["string", "null"]}, "executed_at": {"type": ["string", "null"]}, "executed_by": {"type": ["string", "null"]}, "groups": {"anyOf": [{"type": "array", "prefixItems": [{"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}}, "required": ["id", "name"]}], "minItems": 1, "maxItems": 1}, {"type": "array", "prefixItems": [{"type": "object", "properties": {"id": {"type": "null"}, "name": {"type": ["string", "null"]}}, "required": ["id", "name"]}], "minItems": 1, "maxItems": 1}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}}, "required": ["id", "name", "status", "info", "action_name", "action_label", "executed_at", "executed_by", "groups"]}], "title": "ActionGroupResource"}, "ActionResource": {"type": "object", "properties": {"id": {"type": "string"}, "action": {"type": "string"}, "old_value": {"type": "string"}, "new_value": {"type": "string"}, "field": {"type": "string"}, "status": {"$ref": "#/components/schemas/ActionStatusEnum"}, "tries": {"type": "string"}, "process_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "created_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "completed_at": {"type": ["string", "null"]}, "stats": {"type": "object", "properties": {"total_groups": {"type": "string"}, "pending": {"type": "string"}, "running": {"type": "string"}, "completed": {"type": "string"}, "failed": {"type": "string"}, "skipped": {"type": "string"}}, "required": ["total_groups", "pending", "running", "completed", "failed", "skipped"]}, "groups": {"type": "string"}, "subActions": {"type": "array", "items": {"$ref": "#/components/schemas/ActionResource"}}}, "required": ["id", "action", "old_value", "new_value", "field", "status", "tries", "process_at", "created_at", "completed_at", "stats", "groups", "subActions"], "title": "ActionResource"}, "ActionStatusEnum": {"type": "integer", "description": "| |\n|---|\n| `0` <br/>  |\n| `1` <br/>  |\n| `2` <br/>  |\n| `3` <br/>  |\n| `4` <br/>  |\n| `5` <br/>  |\n| `6` <br/>  |\n| `7` <br/>  |\n| `8` <br/>  |\n| `9` <br/>  |\n| `10` <br/>  |\n| `11` <br/> Intermediate state for new-flow add-admin actions: the provider ACKed the promotion request but real confirmation (promote webhook or group sync) has not yet arrived. Intentionally excluded from failedStatuses() so the pipeline retry endpoint does NOT reset it to PENDING. This state is set explicitly in ActionGroupProcessor — never derived from a provider string via fromString(). |\n| `12` <br/> Terminal state for an operation-plan action that is deliberately not executed: creator protection, would-leave-group-without-admin guard, confirmation timeout, or cascade from an upstream skipped/failed prerequisite in the same group's chain. Reason lives in action_group.info['skip_reason']. Deliberately excluded from failedStatuses() (a retry must NOT reset a SKIPPED row back to PENDING — the skip is definitive) and from isSuccessful() (a SKIPPED row does not represent a completed operation, so it must not be treated as \"the chain advanced\" for purposes that rely on isSuccessful()). Whether SKIPPED counts as \"chain can continue\" is a cascade decision made explicitly by PlanChainCascadeService, not by this enum. |", "enum": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], "title": "ActionStatusEnum"}, "App.Modules.ScheduledMessages.Resources.MessageTemplateResource": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string"}, "value": {"type": "string"}, "mentioned": {"type": "boolean"}, "metrics": {"type": "string"}, "reactions": {"type": "string"}, "votes": {"type": "string"}, "event_responses": {"type": "string", "description": "openspec/changes/surface-event-rsvps-in-campaign-metrics, design D2:\nevent RSVP counts grouped by response value, deduped by the\nresponder's coalesced identity (phone, falling back to lid).\nValues with zero responders never appear (no group produced).\nNOTE: this class is a separate JsonResource from\nApp\\Modules\\GroupManagement\\Resources\\MessageTemplateResource\n(same shape, different namespace) — this is the one actually\ncomposed by ScheduledMessageController::show via\nScheduledMessages\\Resources\\ScheduledMessageResource, so the\nfield is added here too to reach the campaign detail read path."}, "shipping_order": {"type": "string"}, "variations": {"type": "array", "items": {"$ref": "#/components/schemas/MessageTemplateVariationResource"}}}, "required": ["id", "type", "value", "mentioned", "metrics", "reactions", "votes", "event_responses", "shipping_order", "variations"], "title": "App.Modules.ScheduledMessages.Resources.MessageTemplateResource"}, "App.Modules.ScheduledMessages.Resources.ScheduledMessageResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "send_at": {"type": ["string", "null"]}, "status": {"type": "string"}, "is_draft": {"type": ["string", "boolean"]}, "type": {"type": "string"}, "folder": {"type": ["object", "null"], "properties": {"id": {"type": "string"}, "name": {"type": "string"}}, "required": ["id", "name"]}, "audience": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "total_readed": {}, "total_played": {}, "link_clicks": {"type": "integer"}, "whalink_custom_domain": {"type": "string", "description": "track-scheduled-message-link-clicks D4/D7: read back by the\nfrontend's edit/clone hydration (`useEditGroupMessageForm`)."}, "shipping_speed": {"type": "string"}, "campaign_ids": {"type": "string"}, "group_ids": {"type": ["string", "null"]}, "excluded_group_ids": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "static_audience": {"type": "string"}, "campaigns": {"type": "string"}, "groups": {"type": "string"}, "total_groups": {"type": "string"}, "messages": {"type": "array", "items": {"$ref": "#/components/schemas/App.Modules.ScheduledMessages.Resources.MessageTemplateResource"}}, "total_left_after_send": {"type": "string"}, "can_be_edited": {"type": "string"}, "recurrence": {"anyOf": [{"type": "object", "properties": {"enabled": {"type": "boolean"}, "frequency": {"type": "string"}, "interval": {"type": "string"}, "week_days": {"type": "string"}, "end_type": {"type": "string"}, "end_date": {"type": "string"}, "occurrences": {"type": "string"}, "current_occurrence": {"type": "string"}, "only_new_groups": {"type": "string"}, "only_full_groups": {"type": "string"}}, "required": ["enabled", "frequency", "interval", "week_days", "end_type", "end_date", "occurrences", "current_occurrence", "only_new_groups", "only_full_groups"]}, {"type": "object", "properties": {"enabled": {"type": "boolean"}}, "required": ["enabled"]}]}}, "required": ["id", "name", "send_at", "status", "is_draft", "type", "folder", "audience", "total_readed", "total_played", "link_clicks", "whalink_custom_domain", "shipping_speed", "campaign_ids", "group_ids", "excluded_group_ids", "static_audience", "campaigns", "groups", "total_groups", "messages", "total_left_after_send", "can_be_edited", "recurrence"], "title": "App.Modules.ScheduledMessages.Resources.ScheduledMessageResource"}, "AvailableGroupResource": {"type": "object", "properties": {"uid": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "description": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "status": {"anyOf": [{"type": "string"}, {"type": "string", "enum": ["available"]}]}, "campaign_id": {"type": ["string", "null"]}}, "required": ["uid", "name", "description", "status", "campaign_id"], "title": "AvailableGroupResource"}, "CampaignConditionalResource": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string"}, "conditions": {"type": "string"}, "action_type": {"type": "string"}, "redirect_url": {"type": "string"}, "redirect_group_id": {"type": "string"}, "redirect_group_name": {"type": ["string", "null"]}, "is_group_exclusive": {"type": "string"}, "is_active": {"type": "string"}, "order": {"type": "string"}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}}, "required": ["id", "type", "conditions", "action_type", "redirect_url", "redirect_group_id", "is_group_exclusive", "is_active", "order", "created_at", "updated_at"], "title": "CampaignConditionalResource"}, "CampaignParticipantResource": {"type": "object", "properties": {"id": {"type": "string"}, "phone": {"type": "string"}, "name": {"type": "string"}, "lid": {"type": "string"}, "group_id": {"type": "string"}, "group_name": {"type": ["string", "null"]}, "joined_at": {"type": ["string", "null"]}, "left_at": {"type": ["string", "null"]}, "status": {"type": "string"}, "source": {"type": "string"}}, "required": ["id", "phone", "name", "lid", "group_id", "joined_at", "left_at", "status", "source"], "title": "CampaignParticipantResource"}, "CampaignResource": {"type": "object", "properties": {"id": {"type": "string"}, "uuid": {"type": "string"}, "name": {"type": "string"}, "slug": {"type": "string"}, "photo": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "description": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "pixel": {"type": "string"}, "admins": {"type": "string"}, "group_admins": {"type": "string"}, "disconnected_groups": {"type": "string"}, "connection_error_groups": {"type": "string"}, "deviceId": {"type": "string"}, "userId": {"type": "string"}, "type": {"type": "string"}, "groups": {"type": "string"}, "is_active": {"type": "string"}, "redirect_url": {"type": "string"}, "traffic_distribution_type": {"type": ["string", "null"]}, "fill_groups_enabled": {"type": "string"}, "group_numbering_position": {"type": ["string", "null"]}, "anti_bot_verification_enabled": {"type": "string"}, "custom_domain": {"type": "string"}, "captcha_enabled": {"type": "string"}, "virtual_queue_enabled": {"type": "boolean"}, "virtual_queue_rate_per_minute": {"type": "integer"}, "group_name_variations": {"type": "string"}, "moderation": {"type": "object", "properties": {"type": {"type": "string"}, "insults_and_profanity": {"type": "string"}, "negative_comments": {"type": "string"}, "repetitive_spam": {"type": "string"}, "external_links": {"type": "string"}, "promotions_and_sales": {"type": "string"}, "off_topic": {"type": "string"}}, "required": ["type", "insults_and_profanity", "negative_comments", "repetitive_spam", "external_links", "promotions_and_sales", "off_topic"]}, "members_can_send_messages": {"type": "string"}, "clicks_limit": {"type": "string"}, "participants_limit": {"type": "string"}, "backup_groups_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "admins_per_group": {"type": "string"}, "input_tag": {"type": "string"}, "output_tag": {"type": "string"}, "send_always_same_group": {"type": "string"}, "total_participants": {"type": "string"}, "total_clicks": {"type": "string"}, "total_in": {"type": "string"}, "total_out": {"type": "string"}, "total_in_counter": {"type": "integer", "description": "Additive fields backed by the maintained conversion counters (SUM over\ngroups.total_joins/total_leaves), populated by the group sync (Inc.1) and\nthe amortized `groups:backfill-conversion-counters` command (Inc.2) — no\nlonger backfilled on read. These coexist with the calculated `total_in`/\n`total_out` above during the rollout; a later, separate change will drop\nthe calculated fields once the counters are fully populated. `(int)` casts\nthe SUM's possible NULL (all-NULL groups) to 0 for a consistent `number` type.\nScoped by groups.user_id = campaign.user_id — same defensive scoping already\napplied to `groups`/`total_clicks` in CampaignsResource (listing)."}, "total_out_counter": {"type": "integer"}, "auto_create_groups": {"type": "boolean"}, "group_creation_suspended": {"type": ["string", "boolean"]}, "suspended_creator_phones": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "group_creation_has_available_creator": {"type": ["string", "boolean"]}, "api_policy": {"type": "object", "description": "`api-group-campaigns` change, design D8: ONLY for the Grupo API\ntype — spec `api-group-campaign-policy` § \"Campaña de otro tipo\n no tiene política API\" (\"la respuesta no incluye política de\n grupos API, y el consumidor tolera su ausencia\"). `$this->when()`\nomits the key entirely for the other three types, rather than\nemitting it as `null`.", "additionalProperties": {}}}, "required": ["id", "uuid", "name", "slug", "photo", "description", "pixel", "admins", "group_admins", "disconnected_groups", "connection_error_groups", "deviceId", "userId", "type", "groups", "is_active", "redirect_url", "traffic_distribution_type", "fill_groups_enabled", "group_numbering_position", "anti_bot_verification_enabled", "custom_domain", "captcha_enabled", "virtual_queue_enabled", "virtual_queue_rate_per_minute", "group_name_variations", "members_can_send_messages", "clicks_limit", "participants_limit", "backup_groups_count", "admins_per_group", "input_tag", "output_tag", "send_always_same_group", "total_participants", "total_clicks", "total_in", "total_out", "total_in_counter", "total_out_counter", "auto_create_groups", "group_creation_suspended", "suspended_creator_phones", "group_creation_has_available_creator"], "title": "CampaignResource"}, "CampaignWebhookLogResource": {"type": "object", "properties": {"id": {"type": "string"}, "campaign_id": {"type": "string"}, "webhook_id": {"type": "string"}, "webhook_type": {"type": "string"}, "url": {"type": "string"}, "payload": {"type": "string"}, "response_status": {"type": "string"}, "response_body": {"type": "string"}, "execution_time_ms": {"type": "string"}, "success": {"type": "string"}, "error_message": {"type": "string"}, "created_at": {"type": "string"}}, "required": ["id", "campaign_id", "webhook_id", "webhook_type", "url", "payload", "response_status", "response_body", "execution_time_ms", "success", "error_message", "created_at"], "title": "CampaignWebhookLogResource"}, "CampaignWebhookResource": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string"}, "url": {"type": "string"}, "is_active": {"type": "string"}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}}, "required": ["id", "type", "url", "is_active", "created_at", "updated_at"], "title": "CampaignWebhookResource"}, "CampaignsResource": {"type": "object", "properties": {"id": {"type": "string"}, "uuid": {"type": "string"}, "name": {"type": "string"}, "custom_domain": {"type": "string", "description": "Needed so the list can render the branded link (custom domain → /c)\nconsistently with the detail view."}, "photo": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "deviceId": {"type": "string"}, "userId": {"type": "string"}, "type": {"type": "string"}, "is_active": {"type": "string", "description": "Needed by `conversations`' Flows campaign-picker node so it can\nfilter out dead campaigns — same column, same cast as the\nsingular `CampaignResource` (`CampaignResource.php:30`)."}, "groups": {"type": "string"}, "total_clicks": {"type": "string"}, "total_in": {"type": "string"}, "total_in_counter": {"type": "integer", "description": "Additive field backed by the maintained conversion counter (SUM over\ngroups.total_joins), populated by the group sync (Inc.1) and the amortized\n`groups:backfill-conversion-counters` command (Inc.2) — no longer backfilled\non read. Coexists with the calculated `total_in` above during the rollout; a\nlater, separate change will drop the calculated field once the counter is\nfully populated. `(int)` casts the SUM's possible NULL to 0. Note: this\nResource's shape has no `total_out` field — only `total_in_counter` is added\nhere, paralleling the calculated side."}, "admins": {"type": "string"}, "group_admins": {"type": "string"}, "disconnected_groups": {"type": "string"}, "connection_error_groups": {"type": "string"}, "running_actions_count": {"type": "string"}, "pending_actions_count": {"type": "string"}, "pending_sync_groups": {"type": "string"}, "group_creation_suspended": {"type": "boolean", "description": "Suspension state fields — always serialized; the list endpoint does NOT\neager-load administrators, so these are always their default (false / []).\nFull values are only populated in the show/detail endpoint (CampaignResource)."}, "suspended_creator_phones": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "group_creation_has_available_creator": {"type": "boolean"}, "api_open_groups": {"type": "integer", "description": "`api-group-campaigns`. Sólo para el cuarto tipo; para los otros\ntres las claves no viajan y el consumidor tolera su ausencia\n(`$this->when()` omite la clave entera, no la emite en null). El listado las pedía desde el primer día y nadie las emitía: la\ncolumna de administradores quedaba vacía para las campañas API.\nUn gate por incremento no lo atrapa porque cada mitad, por\nseparado, está bien.\n\nHubo además `api_seats_used`/`api_seats_total` para una columna\n\"Ocupación\" que se quitó: medía cuán llenos están los grupos,\nque es una métrica del modelo de LLENAR grupos. En atención\ndedicada un grupo en 8/8 no es un éxito, es uno sin lugar."}, "api_policy": {"type": "object", "properties": {"officialNumber": {"type": ["string", "null"]}, "officialLid": {"type": ["string", "null"]}, "companionNumbers": {"type": "string"}}, "required": ["officialNumber", "officialLid", "companionNumbers"]}}, "required": ["id", "uuid", "name", "custom_domain", "photo", "deviceId", "userId", "type", "is_active", "groups", "total_clicks", "total_in", "total_in_counter", "admins", "group_admins", "disconnected_groups", "connection_error_groups", "running_actions_count", "pending_actions_count", "pending_sync_groups", "group_creation_suspended", "suspended_creator_phones", "group_creation_has_available_creator"], "title": "CampaignsResource"}, "ChannelMetadataResource": {"type": "object", "properties": {"name": {"type": ["string", "null"]}, "description": {"type": ["string", "null"]}, "image": {"type": ["string", "null"]}, "link": {"type": ["string", "null"]}, "admins_numbers": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "participants_numbers": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}, "verified_admin": {"type": "boolean"}, "subscribers_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "participants": {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}}, "required": ["name", "description", "image", "link", "admins_numbers", "participants_numbers", "verified_admin", "subscribers_count", "participants"], "title": "ChannelMetadataResource"}, "ChannelMinResource": {"type": "object", "properties": {"id": {"type": ["string", "null"]}, "uid": {"type": ["string", "null"]}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "description": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "state": {"type": ["string", "null"]}, "subscribers_count": {"type": "integer"}, "invite_link": {"type": ["string", "null"]}, "verification": {"type": ["string", "null"]}, "picture": {"type": ["string", "null"]}, "preview": {"type": ["string", "null"]}, "creation_time": {"type": ["integer", "null"]}, "mute": {"type": ["string", "null"]}, "role": {"type": ["string", "null"]}, "group_id": {"type": ["string", "null"]}}, "required": ["id", "uid", "name", "description", "state", "subscribers_count", "invite_link", "verification", "picture", "preview", "creation_time", "mute", "role", "group_id"], "title": "ChannelMinResource"}, "GroupMetadataResource": {"type": "object", "properties": {"name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "description": {"type": ["string", "null"]}, "image": {"type": ["string", "null"]}, "link": {"type": ["string", "null"]}, "admins_numbers": {"type": "array", "items": {"type": ["string", "null"]}}, "participants_numbers": {"type": "array", "items": {"type": ["string", "null"]}}, "verified_admin": {"type": "boolean"}, "subscribers_count": {"type": "integer"}, "participants": {"type": "array", "items": {}}, "owner": {"type": ["string", "null"]}}, "required": ["name", "description", "image", "link", "admins_numbers", "participants_numbers", "verified_admin", "subscribers_count", "participants", "owner"], "title": "GroupMetadataResource"}, "GroupMinResource": {"type": "object", "properties": {"uid": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "description": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "device_id": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "alias": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "number": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "communityUid": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}}, "required": ["uid", "name", "description", "device_id", "alias", "number", "communityUid"], "title": "GroupMinResource"}, "GroupResource": {"type": "object", "properties": {"id": {"anyOf": [{"type": "string"}, {}]}, "admins_numbers": {"anyOf": [{"type": "string"}, {}]}, "admins": {"anyOf": [{"type": "array", "items": {"type": "object", "properties": {"phone": {"type": ["string", "null"]}, "lid": {"type": ["string", "null"]}, "isConnected": {"type": "boolean"}, "displayPhone": {"type": ["string", "null"]}, "accessDenied": {"type": "boolean"}}, "required": ["phone", "lid", "isConnected", "displayPhone", "accessDenied"]}}, {}]}, "admins_count": {"anyOf": [{"type": "string"}, {}]}, "owner": {"anyOf": [{"type": "string"}, {}]}, "owner_display_phone": {"anyOf": [{"type": "string", "description": "Additive (issue #1159): `owner` may be the creator's lid; this is the\nphone to show, set page-wide by `GroupService::applyOwnerConnected()`.\nNot computed (events, other endpoints) → the raw `owner`, no query."}, {}]}, "owner_connected": {"anyOf": [{"type": "boolean"}, {}]}, "clicks": {"anyOf": [{"type": "string"}, {}]}, "communityUid": {"anyOf": [{"type": "string"}, {}]}, "newsletterUid": {"anyOf": [{"type": "string"}, {}]}, "description": {"anyOf": [{"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, {}]}, "deviceId": {"anyOf": [{"type": "string"}, {}]}, "image": {"anyOf": [{"type": "string"}, {}]}, "isFull": {"anyOf": [{"type": ["string", "boolean"]}, {}]}, "isApi": {"anyOf": [{"type": "boolean"}, {}]}, "link": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "campaign_link": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "campaign_custom_domain": {"type": ["string", "null"], "description": "Custom domain of the owning campaign (if any) so the list can render\nthe branded link (custom domain → /c) instead of the default one."}, "name": {"type": "string"}, "order": {"type": "string"}, "participants_numbers": {"type": "string"}, "participants_count": {"type": "string"}, "status": {"type": "string"}, "uid": {"type": "string"}, "updatedAt": {"type": "string"}, "createdAt": {"type": "string"}, "scheduled_message_count": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "type": {"type": "string"}, "manual_import": {"type": "boolean"}, "origin": {"type": "integer", "enum": [1, 0]}, "lastSyncAt": {"type": ["string", "null"]}}, "required": ["id", "admins_numbers", "admins", "admins_count", "owner", "owner_display_phone", "owner_connected", "clicks", "communityUid", "newsletterUid", "description", "deviceId", "image", "isFull", "isApi", "link", "campaign_link", "campaign_custom_domain", "name", "order", "participants_numbers", "participants_count", "status", "uid", "updatedAt", "createdAt", "scheduled_message_count", "type", "manual_import", "origin", "lastSyncAt"], "additionalProperties": {}, "title": "GroupResource"}, "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"}, "MessageResource": {"type": "object", "properties": {"id": {"type": "string"}, "uid": {"type": "string"}, "type": {"type": "string"}, "value": {}, "scheduledMessage": {"$ref": "#/components/schemas/ScheduledMessageResource"}}, "required": ["id", "uid", "type", "value", "scheduledMessage"], "title": "MessageResource"}, "MessageResponseResource": {"type": "object", "properties": {"message_template_id": {"type": "string"}, "block_type": {"type": "string"}, "group_name": {"type": "string"}, "responder_name": {"type": "string"}, "identity": {"type": "string"}, "identity_type": {"type": "string"}, "response": {"type": "string"}, "response_label": {"type": "string"}, "responded_at": {"type": ["string", "null"]}}, "required": ["message_template_id", "block_type", "group_name", "responder_name", "identity", "identity_type", "response", "response_label", "responded_at"], "title": "MessageResponseResource"}, "MessageTemplateResource": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string"}, "value": {"type": "string"}, "metrics": {"type": "string"}, "reactions": {"type": "string"}, "votes": {"type": "string"}, "event_responses": {"type": "string", "description": "openspec/changes/surface-event-rsvps-in-campaign-metrics, design D2:\nevent RSVP counts grouped by response value, deduped by the\nresponder's coalesced identity (phone, falling back to lid).\nValues with zero responders never appear (no group produced)."}, "shipping_order": {"type": "string"}}, "required": ["id", "type", "value", "metrics", "reactions", "votes", "event_responses", "shipping_order"], "title": "MessageTemplateResource"}, "MessageTemplateVariationResource": {"type": "object", "properties": {"id": {"type": "string"}, "value": {"type": "string"}, "position": {"type": "string"}}, "required": ["id", "value", "position"], "title": "MessageTemplateVariationResource"}, "OperationPlanResource": {"type": "object", "properties": {"id": {"type": "integer"}, "uuid": {"type": "string"}, "campaign_id": {"type": "integer"}, "pipeline_uuid": {"type": ["string", "null"]}, "status": {"type": "string", "description": "Live on-read aggregate (increment 6 — PlanStatusResolver), NOT the\nraw persisted column. Right after confirm this still resolves to\n\"scheduled\" (nothing has run yet), so existing confirm-response\nassertions are unaffected — see OperationPlanConfirmTest."}, "name": {"type": "string"}, "timezone": {"type": "string"}, "window_start": {"type": "string"}, "window_end": {"type": "string"}, "range_start_date": {"type": "string"}, "range_end_date": {"type": "string"}, "daily_cap": {"type": "integer"}, "min_spacing_minutes": {"type": "integer"}, "confirmation_spacing_minutes": {"type": "integer"}, "entry_point": {"type": "string"}, "seed": {"type": ["integer", "null"]}, "idempotency_key": {"type": ["string", "null"]}, "confirmed_at": {"type": ["string", "null"]}, "operations": {"type": "array", "items": {"type": "string"}}}, "required": ["id", "uuid", "campaign_id", "pipeline_uuid", "status", "name", "timezone", "window_start", "window_end", "range_start_date", "range_end_date", "daily_cap", "min_spacing_minutes", "confirmation_spacing_minutes", "entry_point", "seed", "idempotency_key", "confirmed_at", "operations"], "title": "OperationPlanResource"}, "OperationPlanSummaryResource": {"type": "object", "properties": {"id": {"type": "string"}, "uuid": {"type": "string"}, "campaign_id": {"type": "string"}, "pipeline_uuid": {"type": "string"}, "status": {"type": "string"}, "name": {"type": "string"}, "entry_point": {"type": "string"}, "timezone": {"type": "string"}, "range_start_date": {"type": ["string", "null"]}, "range_end_date": {"type": ["string", "null"]}, "daily_cap": {"type": "string"}, "confirmed_at": {"type": ["string", "null"]}, "operation_counts": {"type": "object", "properties": {"total": {"type": "number"}, "pending": {"type": ["number", "array"]}, "running": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "done": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "failed": {"type": "integer", "const": 0}, "skipped": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}, "cancelled": {"anyOf": [{"type": "string"}, {"type": "integer", "enum": [0]}]}}, "required": ["total", "pending", "running", "done", "failed", "skipped", "cancelled"]}}, "required": ["id", "uuid", "campaign_id", "pipeline_uuid", "status", "name", "entry_point", "timezone", "range_start_date", "range_end_date", "daily_cap", "confirmed_at", "operation_counts"], "title": "OperationPlanSummaryResource"}, "ParticipantEventResource": {"type": "object", "properties": {"phone": {"type": "string"}, "whatsapp_id": {"type": "string"}, "event_type": {"type": "string", "enum": ["join", "leave"]}, "event_at": {"type": ["string", "null"]}, "group_id": {"type": "integer"}, "group_name": {"type": "string"}, "country_code": {"type": "string"}, "country_name": {"type": "string"}}, "required": ["phone", "whatsapp_id", "event_type", "event_at", "group_id", "group_name", "country_code", "country_name"], "title": "ParticipantEventResource"}, "ParticipantResource": {"type": "object", "properties": {"id": {"type": "string"}, "phone": {"type": "string"}, "action": {"type": "string"}, "isAdmin": {"type": "string"}, "created_at": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}}, "required": ["id", "phone", "action", "isAdmin", "created_at"], "title": "ParticipantResource"}, "ScheduledMessageEditStatusEnum": {"type": "integer", "description": "What happened to one group when the text of an already-sent scheduled message was edited (`POST scheduled-messages/{scheduledMessage}/edit-sent`). Every group of the last send ends in exactly one of these. Stored in the group's outcome row of the edit in `message_deliveries` (`additional_info.sent_edit_outcome.status`, see `ScheduledMessageSentEditService`), never in `group_message_template.status`: that one is the delivery state, still written by the provider webhooks.\n| |\n|---|\n| `1` <br/> Confirmed delivered, inside the window: the provider accepted the edit. |\n| `2` <br/> Confirmed delivered, but 15 minutes had already passed since it was sent to that group. |\n| `3` <br/> Cloud API device, a channel, or a provider that cannot edit. |\n| `4` <br/> The provider returned an error, or the message never reached the group. |", "enum": [1, 2, 3, 4], "title": "ScheduledMessageEditStatusEnum"}, "ScheduledMessageFolderResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "scheduled_messages_count": {"type": "integer"}}, "required": ["id", "name", "scheduled_messages_count"], "title": "ScheduledMessageFolderResource"}, "ScheduledMessageIndexResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"anyOf": [{"type": "string"}, {"type": "string", "enum": [""]}]}, "send_at": {"type": ["string", "null"]}, "status": {"type": "string"}, "is_draft": {"type": ["string", "boolean"]}, "type": {"type": "string"}, "folder_id": {"type": "string"}, "campaign_ids": {"type": "string"}, "excluded_group_ids": {"anyOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}, "minItems": 0, "maxItems": 0}]}, "can_be_edited": {"type": "string"}, "recurrence": {"anyOf": [{"type": "object", "properties": {"enabled": {"type": "boolean"}, "frequency": {"type": "string"}, "interval": {"type": "string"}, "week_days": {"type": "string"}, "end_type": {"type": "string"}, "end_date": {"type": "string"}, "occurrences": {"type": "string"}, "current_occurrence": {"type": "string"}, "only_new_groups": {"type": "string"}, "only_full_groups": {"type": "string"}}, "required": ["enabled", "frequency", "interval", "week_days", "end_type", "end_date", "occurrences", "current_occurrence", "only_new_groups", "only_full_groups"]}, {"type": "object", "properties": {"enabled": {"type": "boolean"}}, "required": ["enabled"]}]}}, "required": ["id", "name", "send_at", "status", "is_draft", "type", "folder_id", "campaign_ids", "excluded_group_ids", "can_be_edited", "recurrence"], "title": "ScheduledMessageIndexResource"}, "ScheduledMessageResource": {"type": "object", "properties": {"id": {"type": "string"}, "name": {"type": "string"}, "send_at": {"type": "string"}, "status": {"type": "string"}, "type": {"type": "string"}, "audience": {"type": "string"}, "total_readed": {"type": "string"}, "total_played": {"type": "string"}, "campaigns": {"type": "string"}, "groups": {"type": "string"}, "total_groups": {"type": "string"}, "messages": {"type": "array", "items": {"$ref": "#/components/schemas/MessageTemplateResource"}}}, "required": ["id", "name", "send_at", "status", "type", "audience", "total_readed", "total_played", "campaigns", "groups", "total_groups", "messages"], "title": "ScheduledMessageResource"}, "ScheduledMessageRunsResource": {"type": "object", "properties": {"run": {"type": "string"}, "total_groups": {"type": "integer"}, "count_ok": {"type": "integer"}, "count_error": {"type": "integer"}}, "required": ["run", "total_groups", "count_ok", "count_error"], "title": "ScheduledMessageRunsResource"}, "StoreWebhookSubscriptionRequest": {"type": "object", "properties": {"url": {"type": "string", "format": "uri", "maxLength": 2048}, "description": {"type": ["string", "null"], "maxLength": 255}, "events": {"type": "array", "items": {"type": "string", "enum": ["group.created", "group_participant.joined", "group_participant.left", "scheduled_message.finished", "group.blocked", "group.recovered", "scheduled_message.group_delivery_failed", "scheduled_message.response_received", "campaign.status_changed", "pipeline.finished", "poll.voted", "group.invite_link_renewed", "group.invite_link_down", "*"]}, "minItems": 1, "maxItems": 14, "uniqueItems": true}}, "required": ["url", "events"], "title": "StoreWebhookSubscriptionRequest"}, "UpdateWebhookSubscriptionRequest": {"type": "object", "properties": {"url": {"type": "string", "format": "uri", "maxLength": 2048}, "description": {"type": ["string", "null"], "maxLength": 255}, "events": {"type": "array", "items": {"type": "string", "enum": ["group.created", "group_participant.joined", "group_participant.left", "scheduled_message.finished", "group.blocked", "group.recovered", "scheduled_message.group_delivery_failed", "scheduled_message.response_received", "campaign.status_changed", "pipeline.finished", "poll.voted", "group.invite_link_renewed", "group.invite_link_down", "*"]}, "minItems": 1, "maxItems": 14, "uniqueItems": true}, "active": {"type": "boolean"}}, "title": "UpdateWebhookSubscriptionRequest"}, "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": {"type": "string"}}, "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"}, "WebhookSubscriptionWithSecret": {"type": "object", "properties": {"uuid": {"type": "string"}, "url": {"type": "string"}, "description": {"type": ["string", "null"]}, "events": {"type": "array", "items": {"type": "string"}}, "active": {"type": "boolean"}, "inactive_reason": {"type": ["string", "null"]}, "created_at": {"type": ["string", "null"]}, "updated_at": {"type": ["string", "null"]}, "secret": {"type": "string", "description": "Secreto de firma `whsec_…`. Solo viene al crear la suscripción y al rotar el secreto: guardalo."}}, "required": ["uuid", "url", "description", "events", "active", "inactive_reason", "created_at", "updated_at", "secret"], "title": "WebhookSubscriptionWithSecret"}}, "responses": {"AuthorizationException": {"description": "Authorization error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "description": "Error overview."}}, "required": ["message"]}}}}, "ValidationException": {"description": "Validation error", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "description": "Errors overview."}, "errors": {"type": "object", "description": "A detailed description of each field that failed validation.", "additionalProperties": {"type": "array", "items": {"type": "string"}}}}, "required": ["message", "errors"]}}}}, "AuthenticationException": {"description": "Unauthenticated", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "description": "Error overview."}}, "required": ["message"]}}}}, "ModelNotFoundException": {"description": "Not found", "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "description": "Error overview."}}, "required": ["message"]}}}}}}, "webhooks": {"group.created": {"post": {"operationId": "webhook.group_created", "summary": "group.created", "description": "Se creó o se importó un grupo dentro de una campaña de la cuenta.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group.created"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000001", "type": "group.created", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo", "type": "group"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001", "name": "Campaña de ejemplo"}, "source": "created"}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "group_participant.joined": {"post": {"operationId": "webhook.group_participant_joined", "summary": "group_participant.joined", "description": "Una persona entró a un grupo de la cuenta; `campaign` es null si el grupo no es de una campaña.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group_participant.joined"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000002", "type": "group_participant.joined", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001"}, "participant": {"identity": "+5491100000000", "identity_type": "phone", "name": "Ana Pérez"}}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "group_participant.left": {"post": {"operationId": "webhook.group_participant_left", "summary": "group_participant.left", "description": "Una persona salió de un grupo de la cuenta; `campaign` es null si el grupo no es de una campaña.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group_participant.left"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000003", "type": "group_participant.left", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001"}, "participant": {"identity": "+5491100000000", "identity_type": "phone", "name": "Ana Pérez"}}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "scheduled_message.finished": {"post": {"operationId": "webhook.scheduled_message_finished", "summary": "scheduled_message.finished", "description": "Un envío programado terminó, con su resultado agregado.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "scheduled_message.finished"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000004", "type": "scheduled_message.finished", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"scheduled_message": {"uuid": "00000000-0000-4000-8000-000000000004", "name": "Envío de ejemplo"}, "outcome": "partially_failed", "groups": {"total": 10, "failed": 1, "partially_failed": 2}, "occurrence": 1}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "group.blocked": {"post": {"operationId": "webhook.group_blocked", "summary": "group.blocked", "description": "Un grupo quedó inoperable: sin administrador conectado, con el link de invitación inválido o suspendido por WhatsApp.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group.blocked"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000005", "type": "group.blocked", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001"}, "reason": "admin_access_lost"}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "group.recovered": {"post": {"operationId": "webhook.group_recovered", "summary": "group.recovered", "description": "Un grupo que estaba bloqueado volvió a operar.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group.recovered"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000006", "type": "group.recovered", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001"}, "reason": "access_restored"}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "scheduled_message.group_delivery_failed": {"post": {"operationId": "webhook.scheduled_message_group_delivery_failed", "summary": "scheduled_message.group_delivery_failed", "description": "Un envío programado falló en un grupo concreto, con el motivo desagregado.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "scheduled_message.group_delivery_failed"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000007", "type": "scheduled_message.group_delivery_failed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"scheduled_message": {"uuid": "00000000-0000-4000-8000-000000000007"}, "group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo"}, "reason": "device_disconnected", "partial": false, "occurrence": 1}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "scheduled_message.response_received": {"post": {"operationId": "webhook.scheduled_message_response_received", "summary": "scheduled_message.response_received", "description": "Alguien respondió a un envío programado votando una encuesta o respondiendo a un evento.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "scheduled_message.response_received"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000008", "type": "scheduled_message.response_received", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"scheduled_message": {"uuid": "00000000-0000-4000-8000-000000000008"}, "group": {"uid": "120363000000000001@g.us"}, "participant": {"identity": "+5491100000000", "identity_type": "phone", "name": "Ana Pérez"}, "response": {"type": "poll", "options": ["Opción A"], "rsvp": null}}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "campaign.status_changed": {"post": {"operationId": "webhook.campaign_status_changed", "summary": "campaign.status_changed", "description": "Una campaña se activó o se pausó.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "campaign.status_changed"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_00000000000000000000000000000009", "type": "campaign.status_changed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"campaign": {"uuid": "00000000-0000-4000-8000-000000000009", "name": "Campaña de ejemplo"}, "from": "active", "to": "paused"}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "pipeline.finished": {"post": {"operationId": "webhook.pipeline_finished", "summary": "pipeline.finished", "description": "Terminó un pipeline de operaciones sobre grupos, con su resultado agregado y la clave de idempotencia del pedido que lo originó, cuando la hay.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "pipeline.finished"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_0000000000000000000000000000000a", "type": "pipeline.finished", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"campaign": {"uuid": "00000000-0000-4000-8000-00000000000a"}, "pipeline": {"uuid": "00000000-0000-4000-8000-00000000000b", "name": "Pipeline de ejemplo"}, "outcome": "completed", "actions": {"total": 5, "succeeded": 4, "failed": 0, "skipped": 1, "cancelled": 0}, "idempotency_key": "00000000-0000-4000-8000-00000000000d"}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "poll.voted": {"post": {"operationId": "webhook.poll_voted", "summary": "poll.voted", "description": "Un participante votó en una encuesta enviada a un grupo, o cambió su voto.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "poll.voted"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_0000000000000000000000000000000b", "type": "poll.voted", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"poll": {"uid": "3EB0000000000000000001"}, "group": {"uid": "120363000000000001@g.us"}, "scheduled_message": {"uuid": "00000000-0000-4000-8000-000000000004"}, "participant": {"identity": "+5491100000000", "identity_type": "phone", "name": null}, "options": ["Opción A"]}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "group.invite_link_renewed": {"post": {"operationId": "webhook.group_invite_link_renewed", "summary": "group.invite_link_renewed", "description": "El enlace de invitación de un grupo cambió por una renovación, automática al detectarse inválido o pedida por el usuario; en v0 no se publican los cambios que detecta la sincronización ni el enlace inicial al crear el grupo.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group.invite_link_renewed"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_0000000000000000000000000000000c", "type": "group.invite_link_renewed", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo", "type": "group"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001", "name": "Campaña de ejemplo"}, "invite_link": "https://chat.whatsapp.com/EjemploNuevo0000000000001", "previous_invite_link": "https://chat.whatsapp.com/EjemploAnterior000000000001", "trigger": "automatic", "recovered": false}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "group.invite_link_down": {"post": {"operationId": "webhook.group_invite_link_down", "summary": "group.invite_link_down", "description": "El enlace de invitación de un grupo quedó confirmado caído (WhatsApp respondió que no existe y la renovación no consiguió otro); no se publica por errores transitorios ni por grupos prohibidos o suspendidos, y se publica una sola vez por episodio de bloqueo.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "group.invite_link_down"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_0000000000000000000000000000000d", "type": "group.invite_link_down", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"group": {"uid": "120363000000000001@g.us", "name": "Grupo de ejemplo", "type": "group"}, "campaign": {"uuid": "00000000-0000-4000-8000-000000000001", "name": "Campaña de ejemplo"}, "reason": "http_404", "renewal_attempted": true}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}, "webhook.test": {"post": {"operationId": "webhook.webhook_test", "summary": "webhook.test", "description": "Evento de prueba que se envía al pedir la prueba de una suscripción; no se puede suscribir a él.", "tags": ["Webhooks"], "parameters": [{"name": "X-Funnelchat-Event", "in": "header", "required": true, "description": "Tipo del evento; igual al `type` del cuerpo.", "schema": {"type": "string"}, "example": "webhook.test"}, {"name": "X-Funnelchat-Delivery", "in": "header", "required": true, "description": "UUID de este intento de entrega; cambia en cada reintento. Para deduplicar usá el `id` del cuerpo.", "schema": {"type": "string"}, "example": "00000000-0000-4000-8000-000000000001"}, {"name": "X-Funnelchat-Signature", "in": "header", "required": true, "description": "Firma `t=<unix>,v1=<hex>`: HMAC-SHA256 de `t + \".\" + cuerpo` con el secreto completo `whsec_…`.", "schema": {"type": "string"}, "example": "t=1790856000,v1=0000000000000000000000000000000000000000000000000000000000000000"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object"}, "example": {"id": "evt_0000000000000000000000000000000e", "type": "webhook.test", "version": 1, "occurred_at": "2026-10-01T12:00:00Z", "data": {"subscription": "00000000-0000-4000-8000-00000000000c", "sent_at": "2026-10-01T12:00:00Z"}}}}}, "responses": {"2XX": {"description": "Respondé con cualquier 2xx dentro de 10 segundos para confirmar la recepción."}}}}}}