{"openapi":"3.1.0","info":{"title":"Voza API","version":"1.0.0","summary":"Mensajes y llamadas de WhatsApp, por código QR o por la API oficial de Meta.","description":"Los cuerpos de mensajes, llamadas y webhooks siguen el formato de la API oficial de WhatsApp (Meta). Guía completa: https://www.vozaapi.com/docs.","contact":{"url":"https://www.vozaapi.com/docs"}},"servers":[{"url":"https://www.vozaapi.com/v1"}],"security":[{"apiKey":[]}],"tags":[{"name":"Cuenta"},{"name":"Números"},{"name":"Webhooks"},{"name":"Mensajes"},{"name":"Archivos multimedia"},{"name":"Llamadas"},{"name":"Teléfono web"},{"name":"Agentes de voz"}],"paths":{"/account":{"get":{"tags":["Cuenta"],"summary":"La cuenta de la clave, con el plan y los límites","operationId":"getAccount","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/account/usage":{"get":{"tags":["Cuenta"],"summary":"El uso de un mes (UTC), en total y por número","operationId":"getUsage","parameters":[{"name":"month","in":"query","description":"AAAA-MM; el mes actual cuando está vacío.","schema":{"type":"string","pattern":"^\\d{4}-(0[1-9]|1[0-2])$"}}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"422":{"description":"Mes en un formato inválido.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/account/ai-keys":{"get":{"tags":["Agentes de voz"],"summary":"Qué claves de proveedores de IA guardó la cuenta (nunca las claves)","operationId":"getAiKeys","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiKeys"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Agentes de voz"],"summary":"Guarda las claves de proveedores de IA de la cuenta, cifradas","operationId":"updateAiKeys","description":"Solo con una clave de API creada por un propietario de la cuenta. Solo cambian los proveedores enviados; null quita la clave. Cada clave nueva se verifica en el proveedor: si rechaza una (401), no se guarda ninguna clave de la solicitud.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"additionalProperties":false,"properties":{"anthropic":{"type":["string","null"],"minLength":8,"maxLength":500},"deepgram":{"type":["string","null"],"minLength":8,"maxLength":500},"elevenlabs":{"type":["string","null"],"minLength":8,"maxLength":500},"cartesia":{"type":["string","null"],"minLength":8,"maxLength":500}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiKeys"}}}},"403":{"description":"Cuenta bloqueada, o la clave de API no es de un propietario (owner_only).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos inválidos (invalid_request), o un proveedor rechazó la clave (invalid_provider_key; meta.providers dice cuáles).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tts":{"post":{"tags":["Agentes de voz"],"summary":"Una frase dicha por una voz, en audio","operationId":"textToSpeech","description":"Con la clave del proveedor guardada en la cuenta. El audio queda guardado por la voz y el texto: la misma frase vuelve sin esperar (X-Voza-Cache: hit).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtsRequest"}}}},"responses":{"200":{"description":"El audio.","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}},"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Datos inválidos (invalid_request) o la cuenta no tiene la clave del proveedor (missing_provider_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"El proveedor de voz no generó el audio (tts_failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/voices":{"get":{"tags":["Agentes de voz"],"summary":"Las voces de la cuenta en un proveedor de voz","operationId":"listVoices","description":"Con la clave del proveedor guardada en la cuenta, así que las voces clonadas de la cuenta también vienen. La lista se guarda una hora, por cuenta y proveedor.","parameters":[{"name":"provider","in":"query","required":true,"schema":{"type":"string","enum":["elevenlabs","cartesia"]}}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["elevenlabs","cartesia"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Voice"}}}}}}},"422":{"description":"provider no válido (invalid_request) o la cuenta no tiene la clave del proveedor (missing_provider_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"El proveedor de voz no devolvió la lista (voices_failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agents/test-sessions":{"post":{"tags":["Agentes de voz"],"summary":"Una llamada de prueba con un agente, desde el navegador, sin WhatsApp","operationId":"createAgentTestSession","description":"Dé el token al navegador, que envía la oferta SDP en POST /agents/test-sessions/connect. Con number_id, el motor firma con el secreto del agente del número, y los eventos (test: true) van adonde van los del agente del número; sin él, la respuesta trae un secreto solo de esta llamada, y los eventos no se envían. La llamada de prueba cuenta en las sesiones de agente de la cuenta (limits.agent_sessions y limits.agent_tests en GET /account) y termina después de 10 minutos.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_ref","callback_url"],"properties":{"agent_ref":{"type":"string","maxLength":255},"callback_url":{"type":"string","format":"uri","description":"https público."},"number_id":{"type":["string","null"]}}}}}},"responses":{"201":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestSession"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El número no tiene un agente (agent_not_configured).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agents/test-sessions/{session}":{"parameters":[{"name":"session","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["Agentes de voz"],"summary":"Termina la llamada de prueba","operationId":"deleteAgentTestSession","responses":{"204":{"description":"Terminada."},"404":{"description":"La llamada de prueba no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/agents/test-sessions/connect":{"post":{"tags":["Agentes de voz"],"summary":"El navegador envía la oferta SDP de la llamada de prueba (una vez, con el token)","operationId":"connectAgentTestSession","security":[{"agentToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SdpOffer"}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"session":{"$ref":"#/components/schemas/SdpAnswer"}}}}}},"409":{"description":"El token ya se usó (token_used) o el producto rechazó la llamada (agent_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Oferta inválida (invalid_request, invalid_offer) o falta la clave de un proveedor (missing_provider_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"La cuenta ya tiene todas las llamadas de prueba (test_session_limit_reached) o sesiones de agente (agent_limit_reached) simultáneas que puede tener.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"El producto no envió la configuración del agente (agent_config_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Token ausente, inválido o vencido (invalid_monitor_token, invalid_test_token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/monitor/session":{"delete":{"tags":["Agentes de voz"],"summary":"El supervisor que entró con este token sale de la llamada","operationId":"leaveMonitorSession","description":"left es false cuando el supervisor, o la llamada, ya no estaba.","security":[{"agentToken":[]}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"left":{"type":"boolean"}}}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Token ausente, inválido o vencido (invalid_monitor_token, invalid_test_token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El token ya fue usado (token_used).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Agentes de voz"],"summary":"El navegador de un supervisor entra en la llamada (una vez, con el token)","operationId":"joinMonitorSession","security":[{"agentToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SdpOffer"},{"type":"object","properties":{"mode":{"type":"string","enum":["listen","takeover"],"default":"listen","description":"listen: escucha. takeover: entra hablando con quien llamó, en lugar de la IA."}}}]}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"monitor_id":{"type":"string","description":"El id de este supervisor, para takeover y release."},"call_id":{"type":"string"},"session":{"$ref":"#/components/schemas/SdpAnswer"}}}}}},"409":{"description":"El token ya fue usado (token_used), la llamada no está con el agente (call_not_with_agent) o ya tiene todos los supervisores (too_many_monitors).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Oferta inválida (invalid_request, invalid_offer).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Token ausente, inválido o vencido (invalid_monitor_token, invalid_test_token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers":{"get":{"tags":["Números"],"summary":"Los números de la cuenta","operationId":"listNumbers","parameters":[{"name":"external_ref","in":"query","description":"Solo los números con esta referencia tuya.","schema":{"type":"string","maxLength":100}}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Number"}}}}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Números"],"summary":"Crea un número por código QR o conecta un número oficial","operationId":"createNumber","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberCreate"}}}},"responses":{"201":{"description":"Creado. Un número por código QR empieza en starting; uno oficial, en connected. Con un webhook en la solicitud, la respuesta trae también webhook, con el secreto.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberCreated"}}}},"403":{"description":"Cuenta bloqueada (trial_expired, subscription_inactive, account_suspended) o en el límite de números del plan (number_limit_reached).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos inválidos (invalid_request) o Meta rechazó las credenciales (meta_refused).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor o Meta no respondieron (engine_unavailable, meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Números"],"summary":"El número, con el estado leído en el momento","operationId":"getNumber","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Números"],"summary":"Cambia el nombre del número o tu referencia (external_ref)","operationId":"updateNumber","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"name":{"type":"string","maxLength":80},"external_ref":{"type":["string","null"],"maxLength":100,"description":"null elimina la referencia."}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Números"],"summary":"Elimina el número (y desconecta el celular, en un número por código QR)","operationId":"deleteNumber","responses":{"204":{"description":"Eliminado."},"503":{"description":"El motor no respondió; no se eliminó nada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/qr":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Números"],"summary":"El código QR para escanear ahora (solo números por código QR)","operationId":"getNumberQr","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Qr"}}}},"409":{"description":"Número oficial (not_a_qr_number).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor no respondió (engine_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/relink":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"post":{"tags":["Números"],"summary":"Código QR: cambia de celular. Oficial: verifica de nuevo en Meta, sin tocar la configuración de llamadas","operationId":"relinkNumber","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"422":{"description":"Meta rechazó (meta_refused).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor o Meta no respondieron (engine_unavailable, meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/meta":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"put":{"tags":["Números"],"summary":"Nuevo token (y clave secreta) de un número oficial","operationId":"updateNumberMeta","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string"},"app_secret":{"type":["string","null"],"description":"Solo cuando cambió."}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Number"}}}},"409":{"description":"Número por código QR (not_an_official_number).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Meta rechazó (meta_refused).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Meta no respondió (meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calling":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Llamadas"],"summary":"La configuración de llamadas de un número oficial, leída en Meta","operationId":"getCallingSettings","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"calling":{"$ref":"#/components/schemas/CallingSettings"}}}}}},"409":{"description":"Número por código QR (not_an_official_number) o token de Meta rechazado (meta_token_invalid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Meta rechazó la solicitud (whatsapp_refused), con su error en meta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Meta no respondió (meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Llamadas"],"summary":"Cambia la configuración de llamadas de un número oficial en Meta","operationId":"updateCallingSettings","description":"Como en Meta: solo cambian los campos enviados. sip no se acepta.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["calling"],"properties":{"calling":{"$ref":"#/components/schemas/CallingSettings"}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"409":{"description":"Número por código QR (not_an_official_number) o token de Meta rechazado (meta_token_invalid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Configuración inválida (invalid_request) o rechazada por Meta (whatsapp_refused, con su error en meta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Meta no respondió (meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/call-permissions/{wa_id}":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"wa_id","in":"path","required":true,"description":"El número del contacto, con el código del país.","schema":{"type":"string","pattern":"^\\+?\\d{5,20}$"}}],"get":{"tags":["Llamadas"],"summary":"Si el número puede llamar al contacto ahora","operationId":"getCallPermission","description":"Números oficiales: la respuesta de Meta (call_permissions). Números por código QR: siempre granted, porque no hay permiso que pedir.","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallPermission"}}}},"409":{"description":"Meta rechazó el token (meta_token_invalid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"wa_id inválido (invalid_request) o Meta rechazó la solicitud (whatsapp_refused, con su error en meta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Meta no respondió (meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/webhook":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Webhooks"],"summary":"El webhook del número","operationId":"getWebhook","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Webhooks"],"summary":"Define el webhook, cambia su secreto o lo elimina","operationId":"updateWebhook","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":["string","null"],"format":"uri","description":"https público; null elimina el webhook."},"rotate_secret":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/templates":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Mensajes"],"summary":"Las plantillas de mensaje de un número oficial, leídas en Meta, una página a la vez","operationId":"listTemplates","description":"La lista de Meta (message_templates) de la cuenta de WhatsApp Business del número, tal como Meta la da. paging.next y paging.previous apuntan a Voza.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"after","in":"query","description":"El cursor de la página siguiente (paging.cursors.after).","schema":{"type":"string"}},{"name":"before","in":"query","description":"El cursor de la página anterior (paging.cursors.before).","schema":{"type":"string"}},{"name":"fields","in":"query","description":"Los campos de Meta de cada plantilla, separados por comas.","schema":{"type":"string","default":"id,name,language,category,status,components"}},{"name":"name","in":"query","description":"Filtros de Meta: name, status, category y language.","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","examples":["APPROVED"]}},{"name":"category","in":"query","schema":{"type":"string","examples":["UTILITY"]}},{"name":"language","in":"query","schema":{"type":"string","examples":["pt_BR"]}}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"}}}},"409":{"description":"Número por código QR (not_an_official_number) o token de Meta rechazado (meta_token_invalid).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Parámetros no válidos (invalid_request) o rechazados por Meta (whatsapp_refused, con su error en meta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Meta no respondió (meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/messages":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"post":{"tags":["Mensajes"],"summary":"Envía un mensaje, con el cuerpo de Meta","operationId":"sendMessage","parameters":[{"name":"Idempotency-Key","in":"header","description":"Repetir con la misma clave devuelve el primer envío en lugar de enviar de nuevo. Voza guarda la primera respuesta durante 24 horas, en los dos tipos de número.","schema":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_.:-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageRequest"}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"409":{"description":"Número desconectado (number_not_connected), token de Meta rechazado (meta_token_invalid) u otro envío con la misma Idempotency-Key en curso (send_in_progress).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Cuerpo inválido (invalid_request), tipo exclusivo de números oficiales (unsupported_type) o rechazado por Meta (whatsapp_refused).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta, con Retry-After, o de envíos de Meta en un número oficial (rate_limited).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"WhatsApp no aceptó el mensaje (whatsapp_refused), en un número por código QR.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Servicio no disponible (engine_unavailable, number_reconnecting, o meta_unavailable: el envío no llegó a Meta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"El envío tardó demasiado (send_timeout), o Meta no respondió a tiempo y el mensaje puede haberle llegado (meta_timeout): repítelo con la misma Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/media/{media}":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"media","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Archivos multimedia"],"summary":"Los bytes de un archivo multimedia recibido","operationId":"getMedia","responses":{"200":{"description":"El archivo, con su Content-Type.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"El número no existe en esta cuenta, o el archivo multimedia no existe o venció (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"El archivo era demasiado grande para guardarlo (media_too_large).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"WhatsApp no entregó el archivo (media_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor o Meta no respondieron (engine_unavailable, meta_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Llamadas"],"summary":"El registro de llamadas, de las más recientes a las más antiguas","operationId":"listCalls","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Call"}}}}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Llamadas"],"summary":"Una acción de llamada, con el cuerpo de Meta","operationId":"callAction","parameters":[{"name":"Idempotency-Key","in":"header","description":"Repetir con la misma clave devuelve la primera respuesta en lugar de repetir la acción (después de un meta_timeout, por ejemplo). Voza guarda la primera respuesta 24 horas.","schema":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9_.:-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallAction"}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallActionResponse"}}}},"404":{"description":"El número no existe en esta cuenta (not_found), o la llamada no existe o ya terminó (call_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"number_not_connected, call_not_ready, meta_token_invalid u otra acción con la misma Idempotency-Key en curso (action_in_progress).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"invalid_request, not_on_whatsapp o call_failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"channel_limit_reached, lines_busy o rate_limited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"WhatsApp no aceptó la acción, en un número por código QR (call_failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"lines_starting, engine_unavailable o meta_unavailable (la acción no llegó a Meta: puedes repetirla).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"El motor tardó demasiado en responder (call_timeout), o Meta no respondió a tiempo y la acción puede haberle llegado (meta_timeout): repítela con la misma Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/agent":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"get":{"tags":["Agentes de voz"],"summary":"El agente de voz del número, sin el secreto","operationId":"getNumberAgent","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"agent":{"$ref":"#/components/schemas/Agent"}}}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Agentes de voz"],"summary":"Define el agente de voz del número y cuándo atiende","operationId":"updateNumberAgent","description":"Voza no guarda prompt ni configuración: al comienzo de cada llamada, el motor pide la configuración del agente en callback_url. La primera vez, la respuesta trae agent.secret, que firma las solicitudes del motor y los eventos enviados a events_url.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSettings"}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"agent":{"$ref":"#/components/schemas/Agent"}}}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Los agentes de voz no están disponibles en esta instalación (agents_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Agentes de voz"],"summary":"Apaga el agente del número y olvida el secreto","operationId":"deleteNumberAgent","responses":{"204":{"description":"Apagado."},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/agent/secret":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"post":{"tags":["Agentes de voz"],"summary":"Un secreto nuevo para el agente; el anterior deja de valer en el acto","operationId":"rotateNumberAgentSecret","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"agent":{"$ref":"#/components/schemas/Agent"}}}}}},"409":{"description":"El número no tiene un agente (agent_not_configured).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls/{call}/agent":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"call","in":"path","required":true,"description":"El id de la llamada en WhatsApp (call_id) o su id en Voza.","schema":{"type":"string"}}],"post":{"tags":["Agentes de voz"],"summary":"Entrega al agente una llamada entrante que todavía está sonando","operationId":"answerCallWithAgent","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"agent_ref":{"type":"string","maxLength":255,"description":"Otro agente del producto; el del número cuando está vacío."}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"call":{"$ref":"#/components/schemas/Call"}}}}}},"404":{"description":"El número o la llamada no existen en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Alguien ya atendió (call_answered_elsewhere), la llamada no está sonando (call_not_ringing), el número no tiene un agente (agent_not_configured) o el producto rechazó la llamada (agent_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos inválidos (invalid_request) o falta la clave de un proveedor (missing_provider_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"La cuenta ya tiene todas las sesiones de agente simultáneas que puede tener (agent_limit_reached).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"El producto no envió la configuración del agente (agent_config_unavailable).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls/{call}/monitor":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"call","in":"path","required":true,"description":"El id de la llamada en WhatsApp (call_id) o su id en Voza.","schema":{"type":"string"}}],"post":{"tags":["Agentes de voz"],"summary":"Un token corto para que un supervisor escuche la llamada que atendió el agente","operationId":"monitorCall","responses":{"201":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MonitorToken"}}}},"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"404":{"description":"El número o la llamada no existen en esta cuenta (not_found), o el motor ya no la tiene (call_not_found, monitor_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La llamada no está con el agente (call_not_with_agent), todavía se está atendiendo (call_not_ready) u otro supervisor la tomó (not_in_control).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls/{call}/monitor/{monitor}":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"call","in":"path","required":true,"description":"El id de la llamada en WhatsApp (call_id) o su id en Voza.","schema":{"type":"string"}},{"name":"monitor","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["Agentes de voz"],"summary":"Quita a un supervisor de la llamada (la IA vuelve a hablar si la tenía)","operationId":"removeMonitor","description":"left es false cuando el supervisor, o la llamada, ya no estaba.","responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"left":{"type":"boolean"}}}}}},"404":{"description":"El número o la llamada no existen en esta cuenta (not_found), o el motor ya no la tiene (call_not_found, monitor_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La llamada no está con el agente (call_not_with_agent), todavía se está atendiendo (call_not_ready) u otro supervisor la tomó (not_in_control).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls/{call}/whisper":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"call","in":"path","required":true,"description":"El id de la llamada en WhatsApp (call_id) o su id en Voza.","schema":{"type":"string"}}],"post":{"tags":["Agentes de voz"],"summary":"Una instrucción para la IA, que quien llamó no oye","operationId":"whisperToAgent","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","maxLength":2000},"monitor":{"type":"string","description":"El supervisor que la envía, para el evento call.supervision."}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"404":{"description":"El número o la llamada no existen en esta cuenta (not_found), o el motor ya no la tiene (call_not_found, monitor_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La llamada no está con el agente (call_not_with_agent), todavía se está atendiendo (call_not_ready) u otro supervisor la tomó (not_in_control).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls/{call}/takeover":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"call","in":"path","required":true,"description":"El id de la llamada en WhatsApp (call_id) o su id en Voza.","schema":{"type":"string"}}],"post":{"tags":["Agentes de voz"],"summary":"La IA deja de hablar y el micrófono del supervisor pasa a la llamada","operationId":"takeOverCall","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["monitor"],"properties":{"monitor":{"type":"string"}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"404":{"description":"El número o la llamada no existen en esta cuenta (not_found), o el motor ya no la tiene (call_not_found, monitor_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La llamada no está con el agente (call_not_with_agent), todavía se está atendiendo (call_not_ready) u otro supervisor la tomó (not_in_control).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/calls/{call}/release":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}},{"name":"call","in":"path","required":true,"description":"El id de la llamada en WhatsApp (call_id) o su id en Voza.","schema":{"type":"string"}}],"post":{"tags":["Agentes de voz"],"summary":"Devuelve la llamada a la IA","operationId":"releaseCall","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"monitor":{"type":"string"}}}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"404":{"description":"El número o la llamada no existen en esta cuenta (not_found), o el motor ya no la tiene (call_not_found, monitor_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La llamada no está con el agente (call_not_with_agent), todavía se está atendiendo (call_not_ready) u otro supervisor la tomó (not_in_control).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Datos no válidos (invalid_request).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"El motor de agentes no respondió (agents_unavailable) o está en su límite (agents_busy), con el motivo en meta.reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/numbers/{number}/webphone-tokens":{"parameters":[{"name":"number","in":"path","required":true,"description":"El id del número en Voza.","schema":{"type":"string"}}],"post":{"tags":["Teléfono web"],"summary":"Un token de corta duración para el SDK del teléfono web","operationId":"createWebphoneToken","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":80},"minutes":{"type":"integer","minimum":5,"maximum":720,"default":480}}}}}},"responses":{"201":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebphoneToken"}}}},"401":{"description":"Clave ausente, inválida o revocada (invalid_api_key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes de la cuenta (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"El número no existe en esta cuenta (not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webphone/session":{"get":{"tags":["Teléfono web"],"summary":"El número y los servidores ICE del token (usado por el SDK)","operationId":"webphoneSession","security":[{"webphoneToken":[]}],"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebphoneSession"}}}},"401":{"description":"Token ausente, inválido o vencido (invalid_webphone_token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes del token (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webphone/events":{"get":{"tags":["Teléfono web"],"summary":"Los eventos de las llamadas, por Server-Sent Events (usado por el SDK)","operationId":"webphoneEvents","security":[{"webphoneToken":[]}],"parameters":[{"name":"token","in":"query","schema":{"type":"string"},"description":"El token, para EventSource, que no envía encabezados."},{"name":"Last-Event-ID","in":"header","schema":{"type":"string"},"description":"El último evento recibido: el flujo sigue desde el siguiente. EventSource lo envía solo al reconectar."},{"name":"after","in":"query","schema":{"type":"integer"},"description":"Lo mismo que Last-Event-ID, para quien no puede enviar el encabezado."}],"responses":{"200":{"description":"Eventos calls y claimed; retoma con Last-Event-ID.","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Token ausente, inválido o vencido (invalid_webphone_token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de solicitudes del token (rate_limited), con Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webphone/calls":{"post":{"tags":["Teléfono web"],"summary":"Una acción de llamada con el token del teléfono web (usado por el SDK)","operationId":"webphoneCallAction","security":[{"webphoneToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallAction"}}}},"responses":{"200":{"description":"Correcto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallActionResponse"}}}},"404":{"description":"La llamada no existe o ya terminó (call_not_found).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"number_not_connected, call_not_ready, call_answered_elsewhere o meta_token_invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"invalid_request, not_on_whatsapp o call_failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"channel_limit_reached, lines_busy o rate_limited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"WhatsApp no aceptó la acción, en un número por código QR (call_failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"lines_starting, engine_unavailable o meta_unavailable (la acción no llegó a Meta: puedes repetirla).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"El motor tardó demasiado en responder (call_timeout), o Meta no respondió a tiempo y la acción puede haberle llegado (meta_timeout): repítela con la misma Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Token ausente, inválido o vencido (invalid_webphone_token).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Cuenta bloqueada: trial_expired, subscription_inactive o account_suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"messages":{"post":{"summary":"Mensajes recibidos y estados de entrega (sobre de Meta, field: messages)","description":"Sin un 2xx, nuevos intentos con esperas crecientes durante 24 horas, o durante el plazo acordado con Voza para la cuenta (webhook_retry_hours en GET /account, hasta 7 días).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Cualquier 2xx en hasta 10 segundos."}}}},"calls":{"post":{"summary":"Eventos de llamada (sobre de Meta, field: calls)","description":"En una cola propia: sin un 2xx, nuevos intentos después de 5, 15 y 30 segundos; los de una llamada que está sonando (connect, RINGING) desisten a los 2 minutos, y el fin de una llamada sigue después por el plazo de los eventos de mensaje. Una llamada rechazada por encima del límite de llamadas simultáneas llega como terminate, con status REJECTED y voza_reason: channel_limit; una que rechazó el agente, con voza_reason: agent_unavailable y el motivo en voza_detail.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"responses":{"200":{"description":"Cualquier 2xx en hasta 10 segundos."}}}},"call.agent":{"post":{"summary":"Eventos del agente de voz (object: voza): call.agent.started, call.agent.state, call.transcript, call.agent.tool_call, call.metrics, call.supervision, call.agent.error, call.agent.declined y call.agent.ended","description":"En una cola propia, a la events_url del agente (firmado con el secreto del agente) o al webhook del número: los eventos de una llamada salen en orden, uno después del otro. Nuevos intentos en segundos por hasta 2 minutos; call.agent.ended, call.agent.error y call.agent.declined, después, por el plazo de los eventos de mensaje. timestamp en segundos y timestamp_ms en milisegundos.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentEvent"}}}},"responses":{"200":{"description":"Cualquier 2xx en hasta 10 segundos."}}}},"number.status":{"post":{"summary":"Cambio de estado del número (object: voza)","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NumberStatusEvent"}}}},"responses":{"200":{"description":"Cualquier 2xx en hasta 10 segundos."}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"Clave de API vz_…, creada en el panel. Solo en tu servidor."},"webphoneToken":{"type":"http","scheme":"bearer","description":"Token wp_… de POST /numbers/{id}/webphone-tokens. También se acepta en ?token=."},"agentToken":{"type":"http","scheme":"bearer","description":"Token mon_… de POST /numbers/{id}/calls/{call}/monitor, o agt_… de POST /agents/test-sessions. Vale una vez."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Estable: úsalo para decidir qué hacer."},"message":{"type":"string","description":"Para personas; puede cambiar."},"details":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}},"description":"Los errores de cada campo, en invalid_request."},"meta":{"$ref":"#/components/schemas/ErrorMeta"}}}}},"ErrorMeta":{"type":"object","description":"Solo cuando el error vino de Meta (el error de la Graph API) o del motor de los números por código QR (reason).","properties":{"code":{"type":"integer","description":"El código de Meta: 131047 (fuera de la ventana de 24 horas), 190 (token inválido), 138006 (sin permiso para llamar)…"},"subcode":{"type":["integer","null"]},"type":{"type":["string","null"],"examples":["OAuthException"]},"details":{"type":["string","null"],"description":"La explicación de Meta (error_data.details)."},"fbtrace_id":{"type":["string","null"],"description":"Para el soporte de Meta."},"reason":{"type":"string","description":"Por qué rechazó el motor, en un número por código QR, o el motor de agentes.","enum":["unreachable","unknown_session","not_found","not_linked","not_ready","too_large","not_on_whatsapp","invalid_request","lines_busy","whatsapp_refused","restarting","lines_starting","not_connected","timeout","engine_error","agent_config_unavailable","missing_provider_key","invalid_offer","call_not_found","call_ended","call_conflict","call_not_ready","too_many_monitors","monitor_not_found","not_in_control","tts_failed","at_capacity","draining","not_configured","runtime_error"]}}},"Account":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"status":{"type":"string","enum":["trial","active","suspended","canceled"]},"trial_ends_at":{"type":["string","null"],"format":"date-time"},"partner":{"type":"boolean","description":"Cuenta socia (otro producto, límites definidos por Voza): las llamadas no se rechazan por el límite de llamadas simultáneas de la cuenta."},"plan":{"type":["string","null"],"enum":["start","pro","scale",null]},"subscription":{"type":["object","null"],"properties":{"status":{"type":"string","description":"El estado de la suscripción en Stripe: active, past_due, canceled…"},"currency":{"type":"string","enum":["brl","usd"]},"renews_at":{"type":["string","null"],"format":"date-time"},"ends_at":{"type":["string","null"],"format":"date-time"}}},"limits":{"type":"object","properties":{"numbers":{"type":"integer"},"channels":{"type":"integer","description":"Llamadas simultáneas."},"requests_per_minute":{"type":"integer","description":"Solicitudes por minuto en la API, sumando todas las claves de la cuenta."},"agent_sessions":{"type":"integer","description":"Sesiones de agente de voz al mismo tiempo: llamadas atendidas por los agentes y llamadas de prueba."},"agent_tests":{"type":"integer","description":"Cuántas de ellas pueden ser llamadas de prueba."}}},"webhook_retry_hours":{"type":"integer","description":"Durante cuántas horas se reintenta un evento de mensaje que falló (24, o lo acordado con Voza, hasta 168)."}}},"UsageTotals":{"type":"object","properties":{"messages_sent":{"type":"integer"},"messages_received":{"type":"integer"},"calls":{"type":"integer"},"call_seconds":{"type":"integer"},"agent_calls":{"type":"integer","description":"Llamadas que atendió un agente de voz."},"agent_seconds":{"type":"integer","description":"Los segundos de la IA en esas llamadas (sin el tiempo en que un supervisor tenía la llamada)."}}},"Usage":{"type":"object","properties":{"month":{"type":"string","examples":["2026-10"]},"totals":{"$ref":"#/components/schemas/UsageTotals"},"numbers":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/UsageTotals"},{"type":"object","properties":{"number_id":{"type":["string","null"],"description":"null para un número ya eliminado."},"name":{"type":["string","null"]}}}]}}}},"Number":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"external_ref":{"type":["string","null"],"description":"Tu referencia para el número (hasta 100 caracteres), que vuelve en metadata.external_ref de los webhooks."},"type":{"type":"string","enum":["qr","meta"]},"status":{"type":"string","enum":["starting","qr","connected","failed"]},"status_reason":{"$ref":"#/components/schemas/StatusReason"},"phone":{"type":["string","null"],"description":"Los dígitos, con el código de país."},"qr_url":{"type":["string","null"],"description":"La página pública del código QR (solo números por código QR)."},"webhook_url":{"type":["string","null"]},"agent_mode":{"type":"string","enum":["off","always","fallback"],"description":"Cuándo atiende el agente de voz del número (vea GET /numbers/{id}/agent)."},"connected_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"meta":{"type":"object","description":"Solo en los números oficiales.","properties":{"phone_number_id":{"type":"string"},"waba_id":{"type":"string"},"display_phone_number":{"type":["string","null"]},"verified_name":{"type":["string","null"]},"quality_rating":{"type":["string","null"],"enum":["GREEN","YELLOW","RED","UNKNOWN",null]},"calling":{"type":["string","null"],"enum":["enabled","disabled","unavailable",null]},"error":{"type":["string","null"],"description":"Lo que Meta rechazó en la última verificación."}}}}},"NumberCreated":{"allOf":[{"$ref":"#/components/schemas/Number"},{"type":"object","properties":{"webhook":{"allOf":[{"$ref":"#/components/schemas/Webhook"}],"description":"Solo cuando la solicitud trajo un webhook: la dirección y el secreto que firma los eventos."}}}]},"NumberCreate":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":80},"external_ref":{"type":["string","null"],"maxLength":100,"description":"Tu referencia para el número, como el id del canal en tu sistema."},"type":{"type":"string","enum":["qr","meta"],"default":"qr"},"webhook":{"type":"object","properties":{"url":{"type":["string","null"],"format":"uri"}},"description":"El webhook del número (https público), definido antes de que el número se conecte; la respuesta trae el secreto. {id} y {external_ref} en la dirección se reemplazan por el id del número y por la external_ref (codificada para URL; exige external_ref en la solicitud)."},"webhook_url":{"type":["string","null"],"format":"uri","description":"Lo mismo que webhook.url, con los mismos marcadores."},"meta":{"type":"object","description":"Obligatorio con type: meta.","required":["phone_number_id","waba_id","access_token","app_secret"],"properties":{"phone_number_id":{"type":"string","pattern":"^\\d{5,30}$"},"waba_id":{"type":"string","pattern":"^\\d{5,30}$"},"access_token":{"type":"string","description":"Token permanente de un usuario del sistema, con whatsapp_business_messaging y whatsapp_business_management."},"app_secret":{"type":"string","pattern":"^[A-Fa-f0-9]{32}$"}}},"calling":{"oneOf":[{"$ref":"#/components/schemas/CallingSettings"},{"type":"string","const":"keep"}],"description":"Solo con type: meta. Las llamadas se activan con esta configuración; lo que falte toma el valor por defecto de Voza (ENABLED, DEFAULT, ENABLED). keep registra el número sin tocar su configuración de llamadas en Meta."}}},"StatusReason":{"type":["string","null"],"enum":["logged_out","restarting","failed","meta_refused",null],"description":"Por qué el número está en este status: logged_out (el celular desconectó el dispositivo), restarting (el motor está reconectando el número), failed (WhatsApp rechazó el dispositivo) o meta_refused (Meta rechazó el token o el número). Vacío cuando no hay nada que explicar."},"CallingSettings":{"type":"object","description":"El objeto calling de la configuración del número en Meta, sin sip.","properties":{"status":{"type":"string","enum":["ENABLED","DISABLED"]},"call_icon_visibility":{"type":"string","enum":["DEFAULT","DISABLE_ALL"],"description":"El botón de llamada en la conversación."},"callback_permission_status":{"type":"string","enum":["ENABLED","DISABLED"],"description":"Pedir al contacto permiso para devolver la llamada."},"call_hours":{"type":"object","description":"El horario de atención, como en Meta (status, timezone_id, weekly_operating_hours, holiday_schedule)."},"call_icons":{"type":"object","description":"Como en Meta (restrict_to_user_countries)."}}},"CallPermission":{"type":"object","properties":{"messaging_product":{"type":"string"},"permission":{"type":"object","properties":{"status":{"type":"string","enum":["granted","temporary","no_permission"],"description":"En un número por código QR, siempre granted."},"expiration_time":{"type":"integer","description":"Cuándo vence un permiso temporal (Unix)."}}},"actions":{"type":"array","description":"Como en Meta: lo que el número puede hacer ahora (start_call, send_call_permission_request) y los límites.","items":{"type":"object"}}}},"TemplateList":{"type":"object","description":"La respuesta de Meta, tal como la da.","properties":{"data":{"type":"array","items":{"type":"object","description":"Una plantilla, con los campos pedidos: id, name, language, category, status, components…"},"examples":[[{"id":"1234567890","name":"pedido_enviado","language":"pt_BR","category":"UTILITY","status":"APPROVED","components":[{"type":"BODY","text":"Seu pedido {{1}} saiu para entrega."}]}]]},"paging":{"type":"object","properties":{"cursors":{"type":"object","properties":{"before":{"type":"string"},"after":{"type":"string"}}},"next":{"type":"string","description":"La página siguiente, en Voza; ausente en la última."},"previous":{"type":"string","description":"La página anterior, en Voza; ausente en la primera."}}}}},"Qr":{"type":"object","properties":{"status":{"type":"string"},"qr":{"type":["string","null"],"description":"PNG en data URI; null después de conectado."},"qr_url":{"type":"string"}}},"Webhook":{"type":"object","properties":{"url":{"type":["string","null"]},"secret":{"type":["string","null"]}}},"MessageRequest":{"type":"object","required":["to"],"description":"El cuerpo de Meta. Todos los números: text, image, video, audio, document. Solo números oficiales: template, interactive, sticker, location, contacts, reaction y context.","properties":{"messaging_product":{"type":"string","const":"whatsapp"},"recipient_type":{"type":"string","const":"individual"},"to":{"type":"string","examples":["5511987654321"]},"type":{"type":"string","enum":["text","image","video","audio","document","template","interactive","sticker","location","contacts","reaction"],"default":"text"},"text":{"type":"object","properties":{"body":{"type":"string","maxLength":4096},"preview_url":{"type":"boolean"}}},"image":{"$ref":"#/components/schemas/MediaLink"},"video":{"$ref":"#/components/schemas/MediaLink"},"audio":{"$ref":"#/components/schemas/MediaLink"},"document":{"$ref":"#/components/schemas/MediaLink"},"template":{"type":"object","description":"Como en la API de Meta (name, language, components)."},"interactive":{"type":"object","description":"Como en la API de Meta (button, list, cta_url, call_permission_request…)."},"sticker":{"type":"object","description":"Como en la API de Meta (id o link)."},"location":{"type":"object","description":"Como en la API de Meta (latitude, longitude, name, address)."},"contacts":{"type":"array","items":{"type":"object"},"description":"Como en la API de Meta (name, phones…)."},"reaction":{"type":"object","description":"Como en la API de Meta (message_id, emoji)."},"context":{"type":"object","properties":{"message_id":{"type":"string"}},"description":"Responder a un mensaje."}}},"MediaLink":{"type":"object","required":["link"],"properties":{"link":{"type":"string","format":"uri","description":"https público."},"caption":{"type":"string","maxLength":1024},"filename":{"type":"string"},"mime_type":{"type":"string"},"voice":{"type":"boolean","description":"Audio como nota de voz (OGG/Opus)."}}},"MessageResponse":{"type":"object","properties":{"messaging_product":{"type":"string"},"contacts":{"type":"array","items":{"type":"object","properties":{"input":{"type":"string"},"wa_id":{"type":"string"}}}},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}}}}}},"CallAction":{"type":"object","required":["action"],"properties":{"messaging_product":{"type":"string","const":"whatsapp"},"action":{"type":"string","enum":["connect","pre_accept","accept","reject","terminate"]},"to":{"type":"string","description":"En connect."},"call_id":{"type":"string","description":"En las demás acciones."},"session":{"type":"object","properties":{"sdp_type":{"type":"string","enum":["offer","answer"]},"sdp":{"type":"string"}}},"biz_opaque_callback_data":{"type":"string","maxLength":512}}},"CallActionResponse":{"type":"object","properties":{"messaging_product":{"type":"string"},"calls":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"}}},"description":"En connect."},"success":{"type":"boolean"}}},"Call":{"type":"object","properties":{"id":{"type":"integer"},"call_id":{"type":"string"},"direction":{"type":"string","enum":["incoming","outgoing"]},"contact":{"type":"string"},"contact_name":{"type":["string","null"]},"status":{"type":"string","enum":["dialing","ringing","active","completed","missed","rejected","no_answer","failed"]},"end_reason":{"type":["string","null"],"description":"channel_limit (rechazada por encima del límite de llamadas simultáneas), agent_unavailable (el agente no pudo atender, o el producto rechazó la llamada, en always) o lost (sin fin después de 6 horas); null en las demás."},"end_detail":{"type":["string","null"],"description":"Con agent_unavailable, por qué el agente rechazó: product_refused, config_unavailable, missing_provider_key, invalid_offer, at_capacity, draining, account_limit, runtime_unavailable, runtime_error, whatsapp_refused o error."},"started_at":{"type":"string","format":"date-time"},"answered_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"duration":{"type":["integer","null"],"description":"Segundos."},"answered_by":{"type":["string","null"],"enum":["webphone","agent","api",null],"description":"Quién atendió (en una llamada saliente, quién llamó): un teléfono web, el agente de voz o su sistema con la clave de API. El primero se queda con la llamada."},"agent":{"type":["object","null"],"description":"Solo en una llamada que atendió el agente.","properties":{"agent_ref":{"type":"string"},"session_id":{"type":["string","null"]},"seconds":{"type":["integer","null"],"description":"Los segundos de la IA (sin el tiempo de un supervisor), cuando el agente terminó."}}}}},"AgentSettings":{"type":"object","required":["mode","agent_ref","callback_url"],"properties":{"require_fresh_config":{"type":"boolean","default":false,"description":"Exigir una configuración nueva del producto en cada llamada; nunca usar la configuración en caché si falla el callback."},"mode":{"type":"string","enum":["off","always","fallback"],"description":"off: solo cuando el producto entrega la llamada; always: toda llamada entrante; fallback: los teléfonos web suenan primero y el agente atiende si nadie atiende."},"fallback_after_seconds":{"type":["integer","null"],"minimum":5,"maximum":120,"default":15},"agent_ref":{"type":"string","maxLength":255,"description":"El agente en su producto."},"callback_url":{"type":"string","format":"uri","description":"Donde el motor pide la configuración (agent.config) y llama a las herramientas (tool.call). https público."},"events_url":{"type":["string","null"],"format":"uri","description":"Para los eventos del agente; sin ella, el webhook del número."}}},"Agent":{"allOf":[{"$ref":"#/components/schemas/AgentSettings"},{"type":"object","properties":{"secret":{"type":"string","description":"Solo en la creación y en POST /numbers/{id}/agent/secret: firma las solicitudes del motor (X-Voza-Signature, el HMAC-SHA256 de \"{X-Voza-Timestamp}.{cuerpo}\"; rechaza un timestamp a más de 5 minutos de tu reloj) y los eventos enviados a events_url."}}}]},"AiKeys":{"type":"object","description":"Qué proveedores tienen una clave guardada.","properties":{"anthropic":{"type":"boolean"},"deepgram":{"type":"boolean"},"elevenlabs":{"type":"boolean"},"cartesia":{"type":"boolean"}}},"Voice":{"type":"object","properties":{"id":{"type":"string","description":"El voice_id de la voz del agente y de POST /tts."},"name":{"type":"string"},"languages":{"type":"array","items":{"type":"string"},"description":"Los idiomas que indica el proveedor (pt-BR, en…); vacío cuando no lo dice."},"gender":{"type":["string","null"],"description":"male, female o neutral, cuando el proveedor lo dice."},"accent":{"type":["string","null"],"description":"Cuando el proveedor lo dice."},"preview_url":{"type":["string","null"],"format":"uri","description":"Una muestra de la voz, cuando la hay."}}},"TtsRequest":{"type":"object","required":["provider","voice_id","text"],"properties":{"provider":{"type":"string","enum":["elevenlabs","cartesia"]},"voice_id":{"type":"string","maxLength":255},"text":{"type":"string","maxLength":1000},"speed":{"type":"number","minimum":0.25,"maximum":4,"default":1},"model":{"type":["string","null"]},"language":{"type":"string","default":"pt-BR"},"format":{"type":"string","enum":["mp3","wav"],"default":"mp3"}}},"SdpOffer":{"type":"object","required":["session"],"properties":{"session":{"type":"object","required":["sdp_type","sdp"],"properties":{"sdp_type":{"type":"string","const":"offer"},"sdp":{"type":"string","description":"El SDP completo, sin trickle ICE."}}}}},"SdpAnswer":{"type":"object","properties":{"sdp_type":{"type":"string","const":"answer"},"sdp":{"type":"string"}}},"MonitorToken":{"type":"object","properties":{"token":{"type":"string","description":"mon_…, para el navegador del supervisor; vale una vez."},"ice_servers":{"type":"array","items":{"type":"object"},"description":"Para new RTCPeerConnection({ iceServers })."},"expires_at":{"type":"string","format":"date-time"}}},"AgentTestSession":{"type":"object","properties":{"id":{"type":"string"},"token":{"type":"string","description":"agt_…, para el navegador; vale una vez."},"ice_servers":{"type":"array","items":{"type":"object"}},"expires_at":{"type":"string","format":"date-time"},"secret":{"type":"string","description":"Solo sin number_id: el secreto que firma las solicitudes del motor en esta llamada de prueba."}}},"AgentEvent":{"type":"object","properties":{"object":{"type":"string","const":"voza"},"event":{"type":"string","enum":["call.agent.started","call.agent.state","call.transcript","call.agent.tool_call","call.metrics","call.supervision","call.agent.error","call.agent.declined","call.agent.ended"]},"event_id":{"type":"string","description":"El mismo en cada intento: úselo para no procesar un evento dos veces."},"number":{"type":"object","description":"Como en number.status."},"call":{"type":"object","description":"Ausente en una llamada de prueba.","properties":{"id":{"type":"string"},"call_id":{"type":"string"},"direction":{"type":"string"},"contact":{"type":"string"},"contact_name":{"type":["string","null"]},"agent_ref":{"type":"string"},"agent_session_id":{"type":["string","null"]}}},"test_session":{"type":"object","description":"Solo en una llamada de prueba.","properties":{"id":{"type":"string"},"agent_ref":{"type":"string"}}},"test":{"type":"boolean"},"data":{"type":"object","description":"Lo que envió el motor: state (listening, thinking, speaking, handoff, handoff_timeout, supervised); speaker, text, start y end; name, duration_ms y result; las latencias; monitor_id y mode; service, provider, status, category y action de un proveedor que falló (call.agent.error); reason, detail, mode y outcome de una llamada que el agente rechazó (call.agent.declined); y, al final, reason, duration_seconds, ai_seconds, supervised_seconds, transcript, tools y usage."},"timestamp":{"type":"integer","description":"Segundos (Unix)."},"timestamp_ms":{"type":"integer","description":"El mismo instante en milisegundos, para ordenar eventos del mismo segundo."}}},"WebphoneToken":{"type":"object","properties":{"token":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"sdk_url":{"type":"string"}}},"WebphoneSession":{"type":"object","properties":{"session_id":{"type":"string","description":"El id de esta sesión, el mismo del evento claimed."},"label":{"type":["string","null"]},"number":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"phone":{"type":["string","null"]},"status":{"type":"string","enum":["starting","qr","connected","failed"]}}},"ice_servers":{"type":"array","description":"Para new RTCPeerConnection({ iceServers }). Las credenciales del TURN vencen: pide la sesión de nuevo antes de cada llamada.","items":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string"}},"username":{"type":"string"},"credential":{"type":"string"}}}},"expires_at":{"type":"string","format":"date-time"}}},"WebhookEnvelope":{"type":"object","description":"El sobre de Meta. metadata.phone_number_id es el id del número en Voza, y metadata.external_ref, tu referencia, cuando el número tiene una. value trae contacts, messages, statuses o calls, y los errors de Meta, incluso solos.","properties":{"object":{"type":"string","const":"whatsapp_business_account"},"entry":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"changes":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["messages","calls"]},"value":{"type":"object"}}}}}}}}},"NumberStatusEvent":{"type":"object","properties":{"object":{"type":"string","const":"voza"},"event":{"type":"string","enum":["number.status","test"]},"number":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"external_ref":{"type":["string","null"]},"status":{"type":"string"},"status_reason":{"$ref":"#/components/schemas/StatusReason"},"phone":{"type":["string","null"]}}},"timestamp":{"type":"integer"}}}}}}