{
  "openapi": "3.0.0",
  "info": {
    "title": "WhatsMarketing API",
    "description": "API pública de WhatsMarketing: contactos, campañas, conversaciones, automatizaciones e informes, con claves de API y webhooks firmados.",
    "version": "1.0",
    "contact": {}
  },
  "servers": [
    {
      "url": "https://micuenta.whatsmarketing.es/api/v1",
      "description": "Producción"
    }
  ],
  "tags": [
    {
      "name": "Automations",
      "description": "Flujos de disparador, condición y acción definidos en el panel. La API los lista y muestra sus ejecuciones."
    },
    {
      "name": "Campaigns",
      "description": "Campañas con plantillas aprobadas por Meta: crear, elegir la audiencia, ver el coste antes de enviar, enviar ahora, programar o escalonar, pausar y reanudar."
    },
    {
      "name": "Contacts",
      "description": "Las personas con las que habla tu organización: datos, etapa del ciclo de vida, etiquetas, identidades por canal, consentimiento y notas. Un contacto puede tener varias identidades (su WhatsApp, su Instagram, su correo) y todas apuntan a la misma ficha."
    },
    {
      "name": "Conversations",
      "description": "Referencias a las conversaciones de la bandeja: con quién, por qué canal, en qué estado y quién la atiende. El contenido de los mensajes vive en la bandeja; leer y enviar mensajes por API llega en la siguiente versión. `externalConversationId` es un identificador opaco de la bandeja: no deduzcas nada de su forma. `channelType` enumera todos los canales previstos en la plataforma; los que aún no están activos en tu organización simplemente no devuelven conversaciones."
    },
    {
      "name": "Reports",
      "description": "Los informes del panel, listos para tu cuadro de mando: comercial, ciclo de vida, campañas, wallet, equipo y conversaciones."
    }
  ],
  "paths": {
    "/contacts": {
      "get": {
        "operationId": "get_contacts",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "tab",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "leads",
                "in_progress",
                "customers",
                "inactive",
                "no_consent"
              ]
            }
          },
          {
            "name": "lifecycleStageId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "ownerId",
            "required": false,
            "in": "query",
            "schema": {
              "pattern": "^(none|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$",
              "type": "string"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "OTHER",
                "MANUAL",
                "IMPORT",
                "WHATSAPP_INBOUND",
                "CAMPAIGN",
                "WEBSITE_FORM",
                "REFERRAL"
              ]
            }
          },
          {
            "name": "channelType",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "WHATSAPP",
                "INSTAGRAM",
                "MESSENGER",
                "FACEBOOK",
                "TELEGRAM",
                "TIKTOK",
                "WEBCHAT",
                "EMAIL",
                "SMS",
                "WECHAT",
                "VOICE"
              ]
            }
          },
          {
            "name": "tag",
            "required": false,
            "in": "query",
            "schema": {
              "maxLength": 60,
              "type": "string"
            }
          },
          {
            "name": "q",
            "required": false,
            "in": "query",
            "schema": {
              "maxLength": 120,
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "schema": {
              "maxLength": 120,
              "type": "string"
            }
          },
          {
            "name": "days",
            "required": false,
            "in": "query",
            "schema": {
              "type": "number",
              "enum": [
                7,
                30,
                90
              ]
            }
          },
          {
            "name": "ids",
            "required": false,
            "in": "query",
            "schema": {
              "maxItems": 500,
              "type": "array",
              "items": {
                "type": "string",
                "format": "uuid"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar contactos",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                      "fullName": "Laura Pérez",
                      "primaryPhone": "+34612345678",
                      "primaryEmail": "laura@ejemplo.com",
                      "company": "Clínica Sol",
                      "country": "ES",
                      "source": "WEBSITE_FORM",
                      "lifecycleStageId": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f",
                      "lifecycleStage": {
                        "id": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f",
                        "name": "Lead nuevo",
                        "order": 1
                      },
                      "ownerId": null,
                      "owner": null,
                      "optedOut": false,
                      "consent": {
                        "given": true,
                        "at": "2026-10-14T10:20:00.000Z",
                        "how": "WEBSITE_FORM"
                      },
                      "tags": [
                        "web"
                      ],
                      "identities": [
                        {
                          "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
                          "channelType": "WHATSAPP",
                          "externalId": "34612345678"
                        }
                      ],
                      "lastConversation": null,
                      "createdAt": "2026-10-14T10:20:05.000Z",
                      "updatedAt": "2026-10-14T10:20:05.000Z"
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 1,
                    "totalPages": 1
                  },
                  "tabs": {
                    "all": 1,
                    "leads": 1,
                    "in_progress": 0,
                    "customers": 0,
                    "inactive": 0,
                    "no_consent": 0
                  },
                  "summary": {
                    "days": 30,
                    "total": 1,
                    "newInPeriod": 1,
                    "withConsent": 1,
                    "withoutConsent": 0,
                    "consentPct": 100,
                    "leadsNew": 1,
                    "leadsInProgress": 0,
                    "customers": 0,
                    "customersNewInPeriod": 0,
                    "tags": [
                      "web"
                    ]
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:read"
        ],
        "summary": "Listar contactos",
        "description": "Contactos de la organización, paginados y con filtros: pestaña (`tab`), etapa, propietario (`ownerId`, o `none` para los que no tienen), origen, canal, etiqueta, búsqueda libre (`q`) o actividad reciente (`days`). Además de `data` y `meta` trae `tabs` (cuántos hay en cada pestaña) y `summary` (las cifras de cabecera del panel)."
      },
      "post": {
        "operationId": "post_contacts",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContactDto"
              },
              "example": {
                "fullName": "Laura Pérez",
                "primaryPhone": "+34612345678",
                "primaryEmail": "laura@ejemplo.com",
                "company": "Clínica Sol",
                "country": "ES",
                "source": "WEBSITE_FORM",
                "tags": [
                  "web"
                ],
                "consent": {
                  "given": true,
                  "at": "2026-10-14T10:20:00.000Z",
                  "how": "WEBSITE_FORM"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Crear un contacto",
            "content": {
              "application/json": {
                "example": {
                  "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "fullName": "Laura Pérez",
                  "primaryPhone": "+34612345678",
                  "primaryEmail": "laura@ejemplo.com",
                  "company": "Clínica Sol",
                  "country": "ES",
                  "source": "WEBSITE_FORM",
                  "lifecycleStageId": null,
                  "lifecycleStage": null,
                  "ownerId": null,
                  "owner": null,
                  "optedOut": false,
                  "consent": {
                    "given": true,
                    "at": "2026-10-14T10:20:00.000Z",
                    "how": "WEBSITE_FORM"
                  },
                  "tags": [
                    "web"
                  ],
                  "identities": [
                    {
                      "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
                      "channelType": "WHATSAPP",
                      "externalId": "34612345678"
                    }
                  ],
                  "createdAt": "2026-10-14T10:20:05.000Z",
                  "updatedAt": "2026-10-14T10:20:05.000Z"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:write"
        ],
        "summary": "Crear un contacto",
        "description": "Crea la ficha. El teléfono va en formato internacional con prefijo (`+34…`). Si ya existe un contacto con ese teléfono, responde `409 CONTACT_PHONE_EXISTS` con el `contactId` del existente. `consent` registra cuándo y cómo dio consentimiento para recibir mensajes; `note` deja una primera nota interna."
      }
    },
    "/contacts/bulk": {
      "post": {
        "operationId": "post_contacts_bulk",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkContactsDto"
              },
              "example": {
                "ids": [
                  "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b"
                ],
                "addTags": [
                  "evento-madrid"
                ],
                "lifecycleStageId": "9c2a1f00-2b3c-4d5e-8f90-1a2b3c4d5e6f"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Actualizar contactos en lote",
            "content": {
              "application/json": {
                "example": {
                  "updated": 2,
                  "skipped": 0
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:write"
        ],
        "summary": "Actualizar contactos en lote",
        "description": "Hasta 500 contactos por llamada: cambiar de etapa, añadir etiquetas (hasta 20) o reasignar el propietario (`ownerId: null` lo quita). Al menos una de las tres. `skipped` son los ids que no pertenecen a tu organización."
      }
    },
    "/contacts/{id}": {
      "get": {
        "operationId": "get_contacts_by_id",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ver un contacto",
            "content": {
              "application/json": {
                "example": {
                  "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "fullName": "Laura Pérez",
                  "primaryPhone": "+34612345678",
                  "primaryEmail": "laura@ejemplo.com",
                  "company": "Clínica Sol",
                  "country": "ES",
                  "source": "WEBSITE_FORM",
                  "lifecycleStageId": null,
                  "lifecycleStage": null,
                  "ownerId": null,
                  "owner": null,
                  "optedOut": false,
                  "consent": {
                    "given": true,
                    "at": "2026-10-14T10:20:00.000Z",
                    "how": "WEBSITE_FORM"
                  },
                  "tags": [
                    "web"
                  ],
                  "identities": [
                    {
                      "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
                      "channelType": "WHATSAPP",
                      "externalId": "34612345678"
                    }
                  ],
                  "createdAt": "2026-10-14T10:20:05.000Z",
                  "updatedAt": "2026-10-14T10:20:05.000Z"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:read"
        ],
        "summary": "Ver un contacto",
        "description": "La ficha completa: identidades por canal, consentimiento, etiquetas, propietario, etapa y oportunidades abiertas."
      },
      "patch": {
        "operationId": "patch_contacts_by_id",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContactDto"
              },
              "example": {
                "company": "Clínica Sol Fuengirola",
                "tags": [
                  "web",
                  "cliente"
                ],
                "lifecycleStageId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Editar un contacto",
            "content": {
              "application/json": {
                "example": {
                  "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "fullName": "Laura Pérez",
                  "primaryPhone": "+34612345678",
                  "primaryEmail": "laura@ejemplo.com",
                  "company": "Clínica Sol",
                  "country": "ES",
                  "source": "WEBSITE_FORM",
                  "lifecycleStageId": null,
                  "lifecycleStage": null,
                  "ownerId": null,
                  "owner": null,
                  "optedOut": false,
                  "consent": {
                    "given": true,
                    "at": "2026-10-14T10:20:00.000Z",
                    "how": "WEBSITE_FORM"
                  },
                  "tags": [
                    "web"
                  ],
                  "identities": [
                    {
                      "id": "6d7e8f90-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
                      "channelType": "WHATSAPP",
                      "externalId": "34612345678"
                    }
                  ],
                  "createdAt": "2026-10-14T10:20:05.000Z",
                  "updatedAt": "2026-10-14T10:20:05.000Z"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:write"
        ],
        "summary": "Editar un contacto",
        "description": "Todos los campos son opcionales; solo cambia lo que mandas. Cambiar el teléfono a uno que ya tiene otro contacto responde `409 CONTACT_PHONE_EXISTS`. Responde con la ficha actualizada."
      },
      "delete": {
        "operationId": "delete_contacts_by_id",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Eliminar un contacto",
            "content": {
              "application/json": {
                "example": {
                  "deleted": true
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:write"
        ],
        "summary": "Eliminar un contacto",
        "description": "Solo si el contacto no tiene conversaciones, campañas ni ventas; si las tiene, responde `409 CONTACT_HAS_HISTORY` y conviene retirarle el consentimiento (`optedOut: true`) en lugar de borrarlo. Las notas e identidades se eliminan con él."
      }
    },
    "/contacts/{id}/timeline": {
      "get": {
        "operationId": "get_contacts_by_id_timeline",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "conversations",
                "campaigns",
                "notes"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Línea de tiempo de un contacto",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                      "type": "campaign",
                      "at": "2026-10-10T08:00:00.000Z",
                      "campaign": {
                        "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                        "name": "Octubre: promo"
                      },
                      "status": "DELIVERED",
                      "sentAt": "2026-10-10T08:00:02.000Z",
                      "deliveredAt": "2026-10-10T08:00:05.000Z",
                      "readAt": null,
                      "failedAt": null,
                      "errorMessage": null
                    },
                    {
                      "id": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
                      "type": "note",
                      "at": "2026-10-09T17:12:00.000Z",
                      "author": "Ana Gómez",
                      "body": "Pidió presupuesto por teléfono"
                    },
                    {
                      "id": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
                      "type": "stage",
                      "at": "2026-10-09T17:00:00.000Z",
                      "by": "Ana Gómez",
                      "from": "Lead nuevo",
                      "to": "En proceso",
                      "bulk": false
                    },
                    {
                      "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                      "type": "created",
                      "at": "2026-10-01T09:00:00.000Z",
                      "source": "WEBSITE_FORM"
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 4,
                    "totalPages": 1
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:read"
        ],
        "summary": "Línea de tiempo de un contacto",
        "description": "Conversaciones, campañas recibidas, notas, cambios de etapa, consentimiento y alta, en orden cronológico inverso. `type` filtra por `conversations`, `campaigns` o `notes`; cada entrada lleva su `type`."
      }
    },
    "/contacts/{id}/identities": {
      "post": {
        "operationId": "post_contacts_by_id_identities",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddIdentityDto"
              },
              "example": {
                "channelType": "INSTAGRAM",
                "externalId": "laura.perez"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Añadir una identidad de canal",
            "content": {
              "application/json": {
                "example": {
                  "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                  "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "channelId": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                  "channel": {
                    "id": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                    "type": "INSTAGRAM"
                  },
                  "externalId": "laura.perez"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:write"
        ],
        "summary": "Añadir una identidad de canal",
        "description": "Vincula otro canal a la misma ficha: `channelType` es el tipo de canal (`WHATSAPP`, `INSTAGRAM`, `MESSENGER`, `EMAIL`…) y `externalId` el identificador del contacto en ese canal (teléfono sin `+` para WhatsApp, usuario para Instagram, correo para email). Si esa identidad ya pertenece a otro contacto, responde 409."
      }
    },
    "/contacts/{id}/notes": {
      "get": {
        "operationId": "get_contacts_by_id_notes",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar notas de un contacto",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
                      "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                      "authorId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                      "author": {
                        "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                        "fullName": "Ana Gómez"
                      },
                      "body": "Pidió presupuesto por teléfono",
                      "createdAt": "2026-10-09T17:12:00.000Z"
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 1,
                    "totalPages": 1
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:read"
        ],
        "summary": "Listar notas de un contacto",
        "description": "Notas internas del equipo, de la más reciente a la más antigua, con autor y fecha."
      },
      "post": {
        "operationId": "post_contacts_by_id_notes",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContactNoteDto"
              },
              "example": {
                "body": "Llamada hecha: le interesa el plan Pyme."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Añadir una nota",
            "content": {
              "application/json": {
                "example": {
                  "id": "4c5d6e7f-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
                  "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "authorId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                  "author": {
                    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                    "fullName": "Ana Gómez"
                  },
                  "body": "Llamada hecha: le interesa el plan Pyme.",
                  "createdAt": "2026-10-14T11:00:00.000Z"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Contacts"
        ],
        "x-api-key-scopes": [
          "contacts:write"
        ],
        "summary": "Añadir una nota",
        "description": "La nota queda a nombre del usuario que creó la clave de API."
      }
    },
    "/conversations": {
      "get": {
        "operationId": "get_conversations",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "filter",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "unassigned",
                "mine",
                "resolved"
              ]
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "OPEN",
                "PENDING",
                "RESOLVED"
              ]
            }
          },
          {
            "name": "channelId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "channelType",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "WHATSAPP",
                "INSTAGRAM",
                "MESSENGER",
                "FACEBOOK",
                "TELEGRAM",
                "TIKTOK",
                "WEBCHAT",
                "EMAIL",
                "SMS",
                "WECHAT",
                "VOICE"
              ]
            }
          },
          {
            "name": "contactId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "assignedToUserId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "q",
            "required": false,
            "in": "query",
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar conversaciones",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6",
                      "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                      "contact": {
                        "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                        "fullName": "Laura Pérez",
                        "primaryPhone": "+34612345678",
                        "primaryEmail": "laura@ejemplo.com"
                      },
                      "channelId": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                      "channel": {
                        "id": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                        "type": "WHATSAPP"
                      },
                      "externalConversationId": "1842",
                      "status": "OPEN",
                      "initiatedBy": "CONTACT",
                      "assignedToUserId": null,
                      "assignedTo": null,
                      "createdAt": "2026-10-14T10:21:00.000Z",
                      "updatedAt": "2026-10-14T10:21:00.000Z"
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 1,
                    "totalPages": 1
                  },
                  "tabs": {
                    "all": 1,
                    "unassigned": 1,
                    "mine": 0,
                    "resolved": 0
                  },
                  "summary": {
                    "open": 1,
                    "newInPeriod": 1,
                    "newInPreviousPeriod": 0,
                    "unassigned": 1,
                    "oldestWaitingMinutes": 12,
                    "resolvedToday": 0,
                    "resolvedYesterday": 3
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Conversations"
        ],
        "x-api-key-scopes": [
          "conversations:read"
        ],
        "summary": "Listar conversaciones",
        "description": "Referencias a las conversaciones de la bandeja con filtros por pestaña (`filter`: `all`, `unassigned`, `mine`, `resolved`), estado, canal, contacto, persona asignada y búsqueda. Trae `tabs` y `summary` con las cifras de la bandeja."
      }
    },
    "/conversations/{id}": {
      "get": {
        "operationId": "get_conversations_by_id",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ver una conversación",
            "content": {
              "application/json": {
                "example": {
                  "id": "d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                  "contact": {
                    "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                    "fullName": "Laura Pérez",
                    "primaryPhone": "+34612345678",
                    "primaryEmail": "laura@ejemplo.com"
                  },
                  "channelId": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                  "channel": {
                    "id": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                    "type": "WHATSAPP"
                  },
                  "externalConversationId": "1842",
                  "status": "OPEN",
                  "initiatedBy": "CONTACT",
                  "assignedToUserId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                  "assignedTo": {
                    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                    "fullName": "Ana Gómez",
                    "email": "ana@ejemplo.com"
                  },
                  "createdAt": "2026-10-14T10:21:00.000Z",
                  "updatedAt": "2026-10-14T10:25:00.000Z"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Conversations"
        ],
        "x-api-key-scopes": [
          "conversations:read"
        ],
        "summary": "Ver una conversación",
        "description": "La referencia de la conversación: contacto, canal, estado, quién la abrió y quién la atiende. Los mensajes no se devuelven: viven en la bandeja."
      }
    },
    "/automations": {
      "get": {
        "operationId": "get_automations",
        "parameters": [
          {
            "name": "tab",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "active",
                "paused",
                "drafts"
              ]
            }
          },
          {
            "name": "trigger",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "LIFECYCLE_STAGE_ENTERED",
                "CAMPAIGN_REPLIED",
                "NO_RESPONSE_DAYS",
                "WALLET_LOW_BALANCE"
              ]
            }
          },
          {
            "name": "q",
            "required": false,
            "in": "query",
            "schema": {
              "maxLength": 120,
              "type": "string"
            }
          },
          {
            "name": "includeArchived",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar automatizaciones",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
                      "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "name": "Bienvenida a leads nuevos",
                      "status": "ACTIVE",
                      "triggerType": "LIFECYCLE_STAGE_ENTERED",
                      "triggerConfig": {
                        "stage": "Lead nuevo"
                      },
                      "steps": [
                        {
                          "type": "CONDITION",
                          "config": {
                            "kind": "CHANNEL_IS",
                            "value": "WHATSAPP"
                          }
                        },
                        {
                          "type": "ACTION",
                          "config": {
                            "kind": "SEND_TEMPLATE",
                            "value": "bienvenida_es"
                          }
                        }
                      ],
                      "pausedReason": null,
                      "failureCount": 0,
                      "lastRunAt": "2026-10-14T09:30:00.000Z",
                      "templateKey": "welcome",
                      "createdByUserId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                      "createdAt": "2026-09-20T12:00:00.000Z",
                      "updatedAt": "2026-10-14T09:30:00.000Z",
                      "triggerLabel": "Cuando entra en Lead nuevo",
                      "stepsSummary": [
                        "si canal es WhatsApp",
                        "enviar plantilla bienvenida_es"
                      ],
                      "runs7d": 18
                    }
                  ],
                  "summary": {
                    "active": 1,
                    "pausedByFailure": 0,
                    "paused": 0,
                    "drafts": 0,
                    "runs7d": 18,
                    "runs7dPrevious": 11,
                    "templatesSent7d": 18,
                    "templatesCost7d": 0.9,
                    "currency": "EUR",
                    "failures7d": 0,
                    "failureExample": null
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Automations"
        ],
        "x-api-key-scopes": [
          "automations:read"
        ],
        "summary": "Listar automatizaciones",
        "description": "Las automatizaciones de la organización con su disparador, pasos, una descripción en palabras (`triggerLabel`, `stepsSummary`) y las ejecuciones de la última semana. Filtra por pestaña (`tab`), disparador o búsqueda; `includeArchived=true` incluye las archivadas. No se pagina."
      }
    },
    "/automations/{id}": {
      "get": {
        "operationId": "get_automations_by_id",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ver una automatización",
            "content": {
              "application/json": {
                "example": {
                  "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "name": "Bienvenida a leads nuevos",
                  "status": "ACTIVE",
                  "triggerType": "LIFECYCLE_STAGE_ENTERED",
                  "triggerConfig": {
                    "stage": "Lead nuevo"
                  },
                  "steps": [
                    {
                      "type": "CONDITION",
                      "config": {
                        "kind": "CHANNEL_IS",
                        "value": "WHATSAPP"
                      }
                    },
                    {
                      "type": "ACTION",
                      "config": {
                        "kind": "SEND_TEMPLATE",
                        "value": "bienvenida_es"
                      }
                    }
                  ],
                  "pausedReason": null,
                  "failureCount": 0,
                  "lastRunAt": "2026-10-14T09:30:00.000Z",
                  "templateKey": "welcome",
                  "createdByUserId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                  "createdAt": "2026-09-20T12:00:00.000Z",
                  "updatedAt": "2026-10-14T09:30:00.000Z",
                  "triggerLabel": "Cuando entra en Lead nuevo",
                  "stepsSummary": [
                    "si canal es WhatsApp",
                    "enviar plantilla bienvenida_es"
                  ],
                  "runs7d": 18
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Automations"
        ],
        "x-api-key-scopes": [
          "automations:read"
        ],
        "summary": "Ver una automatización",
        "description": "Disparador, configuración y pasos (condición, acción, espera) tal como se definieron en el panel, más las ejecuciones de la última semana."
      }
    },
    "/automations/{id}/logs": {
      "get": {
        "operationId": "get_automations_by_id_logs",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "result",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "completed",
                "waiting",
                "condition",
                "skipped",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ejecuciones de una automatización",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
                      "automationId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
                      "contactId": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                      "contact": {
                        "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                        "fullName": "Laura Pérez",
                        "primaryPhone": "+34612345678"
                      },
                      "triggeredAt": "2026-10-14T09:30:00.000Z",
                      "status": "COMPLETED",
                      "humanMessage": "Plantilla «bienvenida_es» enviada",
                      "resultMessage": null,
                      "waitUntil": null,
                      "conversationReferenceId": null,
                      "templatesSent": 1,
                      "templateCost": 0.05
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 1,
                    "totalPages": 1
                  },
                  "summary": {
                    "runs7d": 18,
                    "completed": 17,
                    "waiting": 0,
                    "conditionNotMet": 1,
                    "skipped": 0,
                    "failed": 0,
                    "templatesSent": 17,
                    "templatesCost": 0.85,
                    "currency": "EUR"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Automations"
        ],
        "x-api-key-scopes": [
          "automations:read"
        ],
        "summary": "Ejecuciones de una automatización",
        "description": "Cada vez que el disparador se cumplió para un contacto: estado (`COMPLETED`, `WAITING`, `CONDITION_NOT_MET`, `SKIPPED_NO_CONSENT`, `FAILED`), explicación en palabras y plantillas enviadas con su coste. Filtra por `result`. `summary` resume la última semana."
      }
    },
    "/campaigns": {
      "get": {
        "operationId": "get_campaigns",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "tab",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "sending",
                "scheduled",
                "drafts",
                "errors",
                "finished"
              ]
            }
          },
          {
            "name": "category",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "MARKETING",
                "UTILITY",
                "AUTHENTICATION"
              ]
            }
          },
          {
            "name": "phoneNumberId",
            "required": false,
            "in": "query",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "name": "q",
            "required": false,
            "in": "query",
            "schema": {
              "maxLength": 100,
              "type": "string"
            }
          },
          {
            "name": "days",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 365,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar campañas",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                      "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                      "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                      "name": "Octubre: promo",
                      "status": "COMPLETED",
                      "scheduledAt": null,
                      "startedAt": "2026-10-10T08:00:00.000Z",
                      "completedAt": "2026-10-10T08:12:00.000Z",
                      "batchSize": null,
                      "batchIntervalMin": null,
                      "nextBatchAt": null,
                      "pausedAt": null,
                      "stopReason": null,
                      "sourceCampaignId": null,
                      "createdAt": "2026-10-09T16:00:00.000Z",
                      "updatedAt": "2026-10-10T08:12:00.000Z",
                      "template": {
                        "name": "promo_octubre",
                        "category": "MARKETING",
                        "language": "es"
                      },
                      "phoneNumber": {
                        "numberE164": "+34600000000",
                        "displayName": "Clínica Sol"
                      },
                      "stats": {
                        "total": 1200,
                        "pending": 0,
                        "sent": 1200,
                        "delivered": 1174,
                        "read": 803,
                        "replied": 96,
                        "failed": 26,
                        "progressPct": 100
                      }
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 1,
                    "totalPages": 1
                  },
                  "tabs": {
                    "all": 1,
                    "sending": 0,
                    "scheduled": 0,
                    "drafts": 0,
                    "errors": 0,
                    "finished": 1
                  },
                  "summary": {
                    "days": 30,
                    "since": "2026-09-14",
                    "campaigns": 1,
                    "sent": 1200,
                    "deliveredPct": 97.8,
                    "readPct": 66.9,
                    "replies": 96,
                    "repliesPct": 8,
                    "spend": 59.85,
                    "spendPerMessage": 0.05
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:read"
        ],
        "summary": "Listar campañas",
        "description": "Campañas con su estado, número emisor, plantilla y cifras (`stats`: enviados, entregados, leídos, respondidos, fallidos). Pestañas (`tab`): `all`, `sending`, `scheduled`, `drafts`, `errors`, `finished`. `summary` resume el periodo (`days`)."
      },
      "post": {
        "operationId": "post_campaigns",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCampaignDto"
              },
              "example": {
                "name": "Octubre: promo",
                "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                "variables": {
                  "1": "{{fullName}}",
                  "2": "15 %"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Crear una campaña (borrador)",
            "content": {
              "application/json": {
                "example": {
                  "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                  "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                  "name": "Octubre: promo",
                  "status": "DRAFT",
                  "scheduledAt": null,
                  "startedAt": null,
                  "completedAt": null,
                  "batchSize": null,
                  "batchIntervalMin": null,
                  "nextBatchAt": null,
                  "pausedAt": null,
                  "stopReason": null,
                  "sourceCampaignId": null,
                  "createdAt": "2026-10-09T16:00:00.000Z",
                  "updatedAt": "2026-10-09T16:00:00.000Z",
                  "template": {
                    "id": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                    "name": "promo_octubre",
                    "category": "MARKETING",
                    "language": "es",
                    "bodyText": "Hola {{1}}, este mes tienes un {{2}} de descuento.",
                    "status": "APPROVED"
                  },
                  "phoneNumber": {
                    "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                    "numberE164": "+34600000000",
                    "displayName": "Clínica Sol",
                    "qualityRating": "GREEN"
                  },
                  "estimatedCost": null,
                  "realCost": 0,
                  "stats": {
                    "total": 0,
                    "pending": 0,
                    "sent": 0,
                    "delivered": 0,
                    "read": 0,
                    "replied": 0,
                    "failed": 0,
                    "progressPct": 0
                  },
                  "errorsByReason": [],
                  "lastReplies": []
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:write"
        ],
        "summary": "Crear una campaña (borrador)",
        "description": "Nombre, número emisor y plantilla aprobada. Si la plantilla tiene variables, `variables` dice de dónde sale cada una (campo del contacto como `{{fullName}}` o texto fijo); sin ellas, el envío responde `400 CAMPAIGN_VARIABLES_REQUIRED`. La campaña nace en borrador: después añade la audiencia, consulta el coste y envía."
      }
    },
    "/campaigns/{id}": {
      "get": {
        "operationId": "get_campaigns_by_id",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ver una campaña",
            "content": {
              "application/json": {
                "example": {
                  "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                  "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                  "name": "Octubre: promo",
                  "status": "DRAFT",
                  "scheduledAt": null,
                  "startedAt": null,
                  "completedAt": null,
                  "batchSize": null,
                  "batchIntervalMin": null,
                  "nextBatchAt": null,
                  "pausedAt": null,
                  "stopReason": null,
                  "sourceCampaignId": null,
                  "createdAt": "2026-10-09T16:00:00.000Z",
                  "updatedAt": "2026-10-09T16:00:00.000Z",
                  "template": {
                    "id": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                    "name": "promo_octubre",
                    "category": "MARKETING",
                    "language": "es",
                    "bodyText": "Hola {{1}}, este mes tienes un {{2}} de descuento.",
                    "status": "APPROVED"
                  },
                  "phoneNumber": {
                    "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                    "numberE164": "+34600000000",
                    "displayName": "Clínica Sol",
                    "qualityRating": "GREEN"
                  },
                  "estimatedCost": null,
                  "realCost": 0,
                  "stats": {
                    "total": 0,
                    "pending": 0,
                    "sent": 0,
                    "delivered": 0,
                    "read": 0,
                    "replied": 0,
                    "failed": 0,
                    "progressPct": 0
                  },
                  "errorsByReason": [],
                  "lastReplies": []
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:read"
        ],
        "summary": "Ver una campaña",
        "description": "Detalle con cifras, plantilla, número, programación, coste estimado y real, errores agrupados por motivo y últimas respuestas."
      }
    },
    "/campaigns/{id}/recipients": {
      "get": {
        "operationId": "get_campaigns_by_id_recipients",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "default": 1,
              "type": "number"
            }
          },
          {
            "name": "pageSize",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "filter",
            "required": false,
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "delivered",
                "read",
                "replied",
                "failed",
                "pending"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Destinatarios de una campaña",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
                      "contact": {
                        "id": "0b1c2d3e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
                        "fullName": "Laura Pérez",
                        "primaryPhone": "+34612345678"
                      },
                      "market": "ES",
                      "status": "DELIVERED",
                      "sentAt": "2026-10-10T08:00:02.000Z",
                      "deliveredAt": "2026-10-10T08:00:05.000Z",
                      "readAt": null,
                      "failedAt": null,
                      "errorMessage": null,
                      "totalCost": 0.05,
                      "coveredByAllowance": false
                    }
                  ],
                  "meta": {
                    "page": 1,
                    "pageSize": 20,
                    "total": 1200,
                    "totalPages": 60
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:read"
        ],
        "summary": "Destinatarios de una campaña",
        "description": "Cada destinatario con su estado (`PENDING`, `SENT`, `DELIVERED`, `READ`, `REPLIED`, `FAILED`), el mercado por el que se tarifó, el coste y el motivo del fallo si lo hubo. `filter` acota por estado."
      },
      "post": {
        "operationId": "post_campaigns_by_id_recipients",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AudienceDto"
              },
              "example": {
                "tag": "campaña-octubre"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Añadir audiencia",
            "content": {
              "application/json": {
                "example": {
                  "total": 1217,
                  "optedOut": 14,
                  "withoutPhone": 3,
                  "unpriceable": 0,
                  "eligible": 1200,
                  "added": 1200,
                  "alreadyIn": 0,
                  "totalRecipients": 1200
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:write"
        ],
        "summary": "Añadir audiencia",
        "description": "Una de cuatro fuentes: lista de ids (`contactIds`, hasta 20.000), una etapa (`lifecycleStageId`), una etiqueta (`tag`) o `all: true` para todos. Solo entran los contactos con consentimiento y teléfono; la respuesta dice cuántos quedaron fuera y por qué, cuántos entraron (`added`) y cuántos ya estaban (`alreadyIn`)."
      }
    },
    "/campaigns/{id}/preview-cost": {
      "get": {
        "operationId": "get_campaigns_by_id_preview_cost",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Coste previsto",
            "content": {
              "application/json": {
                "example": {
                  "currency": "EUR",
                  "recipientCount": 1200,
                  "priceableCount": 1197,
                  "unpriceableCount": 3,
                  "estimatedTotal": 59.85,
                  "byMarket": [
                    {
                      "market": "ES",
                      "label": "España",
                      "recipientCount": 1100,
                      "totalCost": 0.05,
                      "subtotal": 55,
                      "rateEffectiveFrom": "2026-07-01"
                    },
                    {
                      "market": "AR",
                      "label": "Argentina",
                      "recipientCount": 97,
                      "totalCost": 0.05,
                      "subtotal": 4.85,
                      "rateEffectiveFrom": "2026-07-01"
                    }
                  ],
                  "wallet": {
                    "balance": 120,
                    "afterSend": 60.15,
                    "sufficient": true
                  },
                  "includedUtilityRemaining": null
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:read"
        ],
        "summary": "Coste previsto",
        "description": "Antes de enviar: cuántos destinatarios se cobran, el precio final por mensaje en cada mercado destino (según el prefijo del número que recibe) y el total en la moneda de tu organización. Los teléfonos sin prefijo válido no se envían ni se cobran. `wallet.sufficient` dice si el saldo alcanza; `includedUtilityRemaining` son los mensajes Utility incluidos que quedan (solo plantillas Utility)."
      }
    },
    "/campaigns/{id}/send": {
      "post": {
        "operationId": "post_campaigns_by_id_send",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCampaignDto"
              },
              "example": {
                "when": "staggered",
                "batchSize": 200,
                "batchIntervalMin": 10
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Enviar, programar o escalonar",
            "content": {
              "application/json": {
                "example": {
                  "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                  "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                  "name": "Octubre: promo",
                  "status": "DRAFT",
                  "scheduledAt": null,
                  "startedAt": null,
                  "completedAt": null,
                  "batchSize": null,
                  "batchIntervalMin": null,
                  "nextBatchAt": null,
                  "pausedAt": null,
                  "stopReason": null,
                  "sourceCampaignId": null,
                  "createdAt": "2026-10-09T16:00:00.000Z",
                  "updatedAt": "2026-10-09T16:00:00.000Z",
                  "template": {
                    "id": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                    "name": "promo_octubre",
                    "category": "MARKETING",
                    "language": "es",
                    "bodyText": "Hola {{1}}, este mes tienes un {{2}} de descuento.",
                    "status": "APPROVED"
                  },
                  "phoneNumber": {
                    "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                    "numberE164": "+34600000000",
                    "displayName": "Clínica Sol",
                    "qualityRating": "GREEN"
                  },
                  "estimatedCost": null,
                  "realCost": 0,
                  "stats": {
                    "total": 0,
                    "pending": 0,
                    "sent": 0,
                    "delivered": 0,
                    "read": 0,
                    "replied": 0,
                    "failed": 0,
                    "progressPct": 0
                  },
                  "errorsByReason": [],
                  "lastReplies": []
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:write"
        ],
        "summary": "Enviar, programar o escalonar",
        "description": "`when: now` (o sin cuerpo) envía al momento; `scheduled` con `scheduledAt` (ISO 8601 con zona, al menos un minuto en el futuro) la deja programada; `staggered` la reparte en tandas de `batchSize` (10 a 5.000) cada `batchIntervalMin` minutos (1 a 1.440). El coste del lote se cobra de la wallet antes de llamar a Meta; si el saldo no alcanza, responde 400 «Saldo insuficiente en la wallet.» y la campaña queda como estaba. Responde con la campaña y su nuevo estado."
      }
    },
    "/campaigns/{id}/pause": {
      "post": {
        "operationId": "post_campaigns_by_id_pause",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pausar",
            "content": {
              "application/json": {
                "example": {
                  "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                  "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                  "name": "Octubre: promo",
                  "status": "DRAFT",
                  "scheduledAt": null,
                  "startedAt": null,
                  "completedAt": null,
                  "batchSize": null,
                  "batchIntervalMin": null,
                  "nextBatchAt": null,
                  "pausedAt": null,
                  "stopReason": null,
                  "sourceCampaignId": null,
                  "createdAt": "2026-10-09T16:00:00.000Z",
                  "updatedAt": "2026-10-09T16:00:00.000Z",
                  "template": {
                    "id": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                    "name": "promo_octubre",
                    "category": "MARKETING",
                    "language": "es",
                    "bodyText": "Hola {{1}}, este mes tienes un {{2}} de descuento.",
                    "status": "APPROVED"
                  },
                  "phoneNumber": {
                    "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                    "numberE164": "+34600000000",
                    "displayName": "Clínica Sol",
                    "qualityRating": "GREEN"
                  },
                  "estimatedCost": null,
                  "realCost": 0,
                  "stats": {
                    "total": 0,
                    "pending": 0,
                    "sent": 0,
                    "delivered": 0,
                    "read": 0,
                    "replied": 0,
                    "failed": 0,
                    "progressPct": 0
                  },
                  "errorsByReason": [],
                  "lastReplies": []
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:write"
        ],
        "summary": "Pausar",
        "description": "Detiene el envío de lo que falta; lo ya enviado no se puede retirar. Solo con campañas que están enviando."
      }
    },
    "/campaigns/{id}/resume": {
      "post": {
        "operationId": "post_campaigns_by_id_resume",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Reanudar",
            "content": {
              "application/json": {
                "example": {
                  "id": "3a4b5c6d-7e8f-4a9b-8c0d-1e2f3a4b5c6d",
                  "organizationId": "f0e1d2c3-b4a5-4968-8776-655443322110",
                  "phoneNumberId": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                  "templateId": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                  "name": "Octubre: promo",
                  "status": "DRAFT",
                  "scheduledAt": null,
                  "startedAt": null,
                  "completedAt": null,
                  "batchSize": null,
                  "batchIntervalMin": null,
                  "nextBatchAt": null,
                  "pausedAt": null,
                  "stopReason": null,
                  "sourceCampaignId": null,
                  "createdAt": "2026-10-09T16:00:00.000Z",
                  "updatedAt": "2026-10-09T16:00:00.000Z",
                  "template": {
                    "id": "e6f7a8b9-c0d1-4e2f-8a3b-4c5d6e7f8a9b",
                    "name": "promo_octubre",
                    "category": "MARKETING",
                    "language": "es",
                    "bodyText": "Hola {{1}}, este mes tienes un {{2}} de descuento.",
                    "status": "APPROVED"
                  },
                  "phoneNumber": {
                    "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                    "numberE164": "+34600000000",
                    "displayName": "Clínica Sol",
                    "qualityRating": "GREEN"
                  },
                  "estimatedCost": null,
                  "realCost": 0,
                  "stats": {
                    "total": 0,
                    "pending": 0,
                    "sent": 0,
                    "delivered": 0,
                    "read": 0,
                    "replied": 0,
                    "failed": 0,
                    "progressPct": 0
                  },
                  "errorsByReason": [],
                  "lastReplies": []
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Campaigns"
        ],
        "x-api-key-scopes": [
          "campaigns:write"
        ],
        "summary": "Reanudar",
        "description": "Continúa una campaña pausada desde donde se quedó (también las que se pausaron por falta de saldo, una vez recargada la wallet)."
      }
    },
    "/reports/comercial": {
      "get": {
        "operationId": "get_reports_comercial",
        "parameters": [
          {
            "name": "days",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 365,
              "default": 30,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Informe comercial",
            "content": {
              "application/json": {
                "example": {
                  "period": {
                    "days": 30,
                    "since": "2026-09-14"
                  },
                  "open": {
                    "count": 12,
                    "value": 18400
                  },
                  "wonInPeriod": {
                    "count": 41,
                    "value": 61200
                  },
                  "lostInPeriod": {
                    "count": 9,
                    "value": 7300
                  },
                  "conversionRate": 82,
                  "previous": {
                    "wonCount": 35,
                    "wonValue": 50100,
                    "conversionRate": 79.5
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Reports"
        ],
        "x-api-key-scopes": [
          "reports:read"
        ],
        "summary": "Informe comercial",
        "description": "Oportunidades abiertas, ganadas y perdidas en el periodo (`days`: 7, 30 o 90), con su importe, la tasa de conversión y el periodo anterior para comparar."
      }
    },
    "/reports/lifecycle": {
      "get": {
        "operationId": "get_reports_lifecycle",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Informe de ciclo de vida",
            "content": {
              "application/json": {
                "example": [
                  {
                    "stage": "Lead nuevo",
                    "order": 1,
                    "count": 318
                  },
                  {
                    "stage": "En proceso",
                    "order": 2,
                    "count": 96
                  },
                  {
                    "stage": "Cliente",
                    "order": 3,
                    "count": 204
                  },
                  {
                    "stage": null,
                    "order": null,
                    "count": 12
                  }
                ]
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Reports"
        ],
        "x-api-key-scopes": [
          "reports:read"
        ],
        "summary": "Informe de ciclo de vida",
        "description": "Cuántos contactos hay en cada etapa; `stage: null` son los que no tienen etapa."
      }
    },
    "/reports/campanas": {
      "get": {
        "operationId": "get_reports_campanas",
        "parameters": [
          {
            "name": "days",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 365,
              "default": 30,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Informe de campañas",
            "content": {
              "application/json": {
                "example": {
                  "period": {
                    "days": 30,
                    "since": "2026-09-14"
                  },
                  "campaigns": 4,
                  "recipientsByStatus": {
                    "SENT": 120,
                    "DELIVERED": 3100,
                    "READ": 2210,
                    "REPLIED": 260,
                    "FAILED": 48
                  },
                  "cost": {
                    "total": 285.9
                  },
                  "previous": {
                    "recipients": 2900,
                    "costTotal": 231.4
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Reports"
        ],
        "x-api-key-scopes": [
          "reports:read"
        ],
        "summary": "Informe de campañas",
        "description": "Campañas del periodo, destinatarios por estado y gasto total, con el periodo anterior para comparar."
      }
    },
    "/reports/wallet": {
      "get": {
        "operationId": "get_reports_wallet",
        "parameters": [
          {
            "name": "days",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 365,
              "default": 30,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Informe de la wallet",
            "content": {
              "application/json": {
                "example": {
                  "period": {
                    "days": 30,
                    "since": "2026-09-14"
                  },
                  "currentBalance": 120,
                  "currency": "EUR",
                  "byType": [
                    {
                      "type": "TOPUP",
                      "count": 2,
                      "amount": 400
                    },
                    {
                      "type": "CAMPAIGN",
                      "count": 4,
                      "amount": -285.9
                    }
                  ]
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Reports"
        ],
        "x-api-key-scopes": [
          "reports:read"
        ],
        "summary": "Informe de la wallet",
        "description": "Saldo actual y movimientos del periodo agrupados por tipo (recargas, campañas, mensajes Service fuera de la franquicia, agentes IA…). Importes finales."
      }
    },
    "/reports/agentes": {
      "get": {
        "operationId": "get_reports_agentes",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Informe del equipo",
            "content": {
              "application/json": {
                "example": [
                  {
                    "userId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                    "fullName": "Ana Gómez",
                    "email": "ana@ejemplo.com",
                    "contactsOwned": 140,
                    "openConversations": 6,
                    "dealsOpen": 4,
                    "dealsWon": 17
                  }
                ]
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Reports"
        ],
        "x-api-key-scopes": [
          "reports:read"
        ],
        "summary": "Informe del equipo",
        "description": "Por cada persona del equipo: contactos de los que es propietaria, conversaciones abiertas y oportunidades abiertas y ganadas."
      }
    },
    "/reports/conversaciones": {
      "get": {
        "operationId": "get_reports_conversaciones",
        "parameters": [
          {
            "name": "days",
            "required": false,
            "in": "query",
            "schema": {
              "minimum": 1,
              "maximum": 365,
              "default": 30,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Informe de conversaciones",
            "content": {
              "application/json": {
                "example": {
                  "period": {
                    "days": 30,
                    "since": "2026-09-14"
                  },
                  "byStatus": {
                    "OPEN": 14,
                    "PENDING": 3,
                    "RESOLVED": 2193
                  },
                  "newInPeriod": 2210,
                  "previous": {
                    "newInPeriod": 1980
                  },
                  "byChannel": [
                    {
                      "channel": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
                      "name": "WhatsApp +34 600 000 000",
                      "count": 2010
                    },
                    {
                      "channel": null,
                      "name": "Sin canal",
                      "count": 200
                    }
                  ]
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "tags": [
          "Reports"
        ],
        "x-api-key-scopes": [
          "reports:read"
        ],
        "summary": "Informe de conversaciones",
        "description": "Conversaciones por estado y por canal, nuevas en el periodo y el periodo anterior para comparar."
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "scheme": "bearer",
        "bearerFormat": "wm_live_…",
        "type": "http",
        "description": "Clave de API creada en micuenta → Integraciones → Webhooks y API."
      }
    },
    "schemas": {
      "SendCampaignDto": {
        "type": "object",
        "properties": {
          "when": {
            "type": "string",
            "enum": [
              "now",
              "scheduled",
              "staggered"
            ]
          },
          "scheduledAt": {
            "type": "string"
          },
          "batchSize": {
            "type": "number",
            "minimum": 10,
            "maximum": 5000
          },
          "batchIntervalMin": {
            "type": "number",
            "minimum": 1,
            "maximum": 1440
          }
        }
      },
      "AudienceDto": {
        "type": "object",
        "properties": {
          "contactIds": {
            "minItems": 1,
            "maxItems": 20000,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "lifecycleStageId": {
            "type": "string",
            "format": "uuid"
          },
          "all": {
            "type": "boolean"
          },
          "tag": {
            "type": "string",
            "maxLength": 60
          }
        }
      },
      "CreateCampaignDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2
          },
          "phoneNumberId": {
            "type": "string",
            "format": "uuid"
          },
          "templateId": {
            "type": "string",
            "format": "uuid"
          },
          "scheduledAt": {
            "type": "string"
          },
          "variables": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "required": [
          "name",
          "phoneNumberId",
          "templateId"
        ]
      },
      "CreateContactNoteDto": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "body"
        ]
      },
      "AddIdentityDto": {
        "type": "object",
        "properties": {
          "channelType": {
            "type": "string",
            "enum": [
              "WHATSAPP",
              "INSTAGRAM",
              "MESSENGER",
              "FACEBOOK",
              "TELEGRAM",
              "TIKTOK",
              "WEBCHAT",
              "EMAIL",
              "SMS",
              "WECHAT",
              "VOICE"
            ]
          },
          "externalId": {
            "type": "string"
          }
        },
        "required": [
          "channelType",
          "externalId"
        ]
      },
      "UpdateContactDto": {
        "type": "object",
        "properties": {
          "fullName": {
            "type": "string",
            "maxLength": 160
          },
          "primaryPhone": {
            "type": "string",
            "maxLength": 32
          },
          "primaryEmail": {
            "type": "string",
            "format": "email"
          },
          "company": {
            "type": "string",
            "maxLength": 160
          },
          "country": {
            "type": "string",
            "maxLength": 2
          },
          "source": {
            "enum": [
              "OTHER",
              "MANUAL",
              "IMPORT",
              "WHATSAPP_INBOUND",
              "CAMPAIGN",
              "WEBSITE_FORM",
              "REFERRAL"
            ],
            "type": "string"
          },
          "lifecycleStageId": {
            "type": "string",
            "format": "uuid"
          },
          "ownerId": {
            "type": "string",
            "format": "uuid"
          },
          "optedOut": {
            "type": "boolean"
          },
          "consent": {
            "$ref": "#/components/schemas/ConsentDto"
          },
          "tags": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            }
          }
        }
      },
      "ConsentDto": {
        "type": "object",
        "properties": {
          "given": {
            "type": "boolean"
          },
          "at": {
            "type": "string"
          },
          "how": {
            "type": "string",
            "enum": [
              "OTHER",
              "WEBSITE_FORM",
              "PHONE",
              "WHATSAPP_REPLY",
              "CONTRACT"
            ]
          }
        },
        "required": [
          "given"
        ]
      },
      "BulkContactsDto": {
        "type": "object",
        "properties": {
          "ids": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "lifecycleStageId": {
            "type": "string",
            "format": "uuid"
          },
          "addTags": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "ownerId": {
            "type": "string",
            "nullable": true,
            "format": "uuid"
          }
        },
        "required": [
          "ids"
        ]
      },
      "CreateContactDto": {
        "type": "object",
        "properties": {
          "fullName": {
            "type": "string",
            "maxLength": 160
          },
          "primaryPhone": {
            "type": "string",
            "maxLength": 32
          },
          "primaryEmail": {
            "type": "string",
            "format": "email"
          },
          "company": {
            "type": "string",
            "maxLength": 160
          },
          "country": {
            "type": "string",
            "maxLength": 2
          },
          "source": {
            "type": "string",
            "enum": [
              "OTHER",
              "MANUAL",
              "IMPORT",
              "WHATSAPP_INBOUND",
              "CAMPAIGN",
              "WEBSITE_FORM",
              "REFERRAL"
            ]
          },
          "lifecycleStageId": {
            "type": "string",
            "format": "uuid"
          },
          "ownerId": {
            "type": "string",
            "format": "uuid"
          },
          "optedOut": {
            "type": "boolean"
          },
          "consent": {
            "$ref": "#/components/schemas/ConsentDto"
          },
          "tags": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "note": {
            "type": "string",
            "maxLength": 4000
          }
        }
      }
    }
  },
  "externalDocs": {
    "url": "https://developer.whatsmarketing.es/es/referencia/",
    "description": "Developer Hub"
  }
}