{
  "openapi": "3.0.3",
  "info": {
    "title": "Zavu Unified Messaging Layer API",
    "version": "0.2.0",
    "description": "Unified multi-channel messaging API for Zavu.\n\nSupported channels:\n- **SMS**: Simple text messages\n- **WhatsApp**: Rich messaging with media, buttons, lists, CTA URL buttons, location requests, and templates\n- **Telegram**: Bot messaging with text, media, and interactive elements\n- **Email**: Transactional emails via Amazon SES\n\nDesign goals:\n- Simple `send()` entrypoint for developers\n- Project-level authentication via Bearer token\n- Support for all WhatsApp message types (text, image, video, audio, document, sticker, location, contact, buttons, list, cta_url, location_request, reaction, template)\n- If a non-text message type is sent, WhatsApp channel is used automatically\n- 24-hour WhatsApp conversation window enforcement\n- Universal `to` field accepts phone numbers (E.164), email addresses, or numeric chat IDs (Telegram/Instagram/Messenger)\n"
  },
  "servers": [
    {
      "url": "https://api.zavu.dev"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "parameters": {
      "SenderHeader": {
        "name": "Zavu-Sender",
        "in": "header",
        "required": false,
        "description": "Optional sender profile ID. If omitted, the project's default sender will be used.",
        "schema": {
          "type": "string",
          "example": "sender_12345"
        }
      },
      "MessageIdParam": {
        "name": "messageId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "SenderIdParam": {
        "name": "senderId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "TemplateIdParam": {
        "name": "templateId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "ContactIdParam": {
        "name": "contactId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "ConversationIdParam": {
        "name": "conversationId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "BroadcastIdParam": {
        "name": "broadcastId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "BroadcastContactIdParam": {
        "name": "contactId",
        "in": "path",
        "required": true,
        "description": "Broadcast contact ID (not the global contact ID)",
        "schema": {
          "type": "string"
        }
      },
      "PhoneNumberIdParam": {
        "name": "phoneNumberId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "InvitationIdParam": {
        "name": "invitationId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "FlowIdParam": {
        "name": "flowId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "ToolIdParam": {
        "name": "toolId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "KnowledgeBaseIdParam": {
        "name": "kbId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "DocumentIdParam": {
        "name": "docId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "AddressIdParam": {
        "name": "addressId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "RegulatoryDocumentIdParam": {
        "name": "documentId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "UrlIdParam": {
        "name": "urlId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "SubAccountIdParam": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Sub-account ID.",
        "schema": {
          "type": "string"
        }
      },
      "SubAccountApiKeyIdParam": {
        "name": "keyId",
        "in": "path",
        "required": true,
        "description": "API key ID.",
        "schema": {
          "type": "string"
        }
      },
      "TenDlcBrandIdParam": {
        "name": "brandId",
        "in": "path",
        "required": true,
        "description": "10DLC brand ID.",
        "schema": {
          "type": "string"
        }
      },
      "TenDlcCampaignIdParam": {
        "name": "campaignId",
        "in": "path",
        "required": true,
        "description": "10DLC campaign ID.",
        "schema": {
          "type": "string"
        }
      },
      "TenDlcAssignmentIdParam": {
        "name": "assignmentId",
        "in": "path",
        "required": true,
        "description": "Phone number assignment ID.",
        "schema": {
          "type": "string"
        }
      },
      "FunctionIdParam": {
        "name": "functionId",
        "in": "path",
        "required": true,
        "description": "Zavu Function ID.",
        "schema": {
          "type": "string"
        }
      },
      "FunctionDeploymentIdParam": {
        "name": "deploymentId",
        "in": "path",
        "required": true,
        "description": "Function deployment ID.",
        "schema": {
          "type": "string"
        }
      },
      "CallIdParam": {
        "name": "callId",
        "in": "path",
        "required": true,
        "description": "Voice call ID.",
        "schema": {
          "type": "string"
        }
      },
      "AgentIdParam": {
        "name": "agentId",
        "in": "path",
        "required": true,
        "description": "Agent ID.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "FunctionTrigger": {
        "type": "object",
        "description": "A subscription that runs a Zavu Function when a messaging event fires.",
        "required": [
          "id",
          "functionId",
          "eventType",
          "active",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "functionId": {
            "type": "string"
          },
          "eventType": {
            "type": "string",
            "description": "Event type that fires the function. See GET /v1/functions/event-types for the supported list. The special type `cron` fires on a schedule instead of a messaging event and carries a `cron` expression."
          },
          "senderId": {
            "type": "string",
            "nullable": true,
            "description": "Restrict the trigger to a single sender. Null means all senders in the project."
          },
          "active": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "cron": {
            "type": "string",
            "nullable": true,
            "description": "5-field cron expression (minute hour day-of-month month day-of-week), evaluated in UTC. Present only on `cron` triggers.",
            "example": "*/15 * * * *"
          },
          "nextRunAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Next scheduled fire time. Present only on `cron` triggers."
          },
          "lastRunAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last time the schedule fired. Null until the first fire."
          }
        }
      },
      "DocumentUpdateRequest": {
        "type": "object",
        "description": "Fields to update on a knowledge base document. Updating content reprocesses the document for RAG.",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 200
          },
          "content": {
            "type": "string",
            "maxLength": 500000
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "example": "invalid_request"
          },
          "message": {
            "type": "string",
            "example": "Phone number is invalid"
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "MessageStatus": {
        "type": "string",
        "enum": [
          "queued",
          "sending",
          "sent",
          "delivered",
          "read",
          "failed",
          "received",
          "pending_url_verification"
        ]
      },
      "Channel": {
        "type": "string",
        "description": "Delivery channel. Use 'auto' for intelligent routing.",
        "enum": [
          "auto",
          "sms",
          "sms_oneway",
          "whatsapp",
          "telegram",
          "email",
          "instagram",
          "messenger",
          "voice"
        ]
      },
      "MessageType": {
        "type": "string",
        "description": "Type of message. Non-text types are supported by WhatsApp and Telegram (varies by type).\n\n`location_request` asks the recipient to share their location and is WhatsApp-only. It takes no `content` object — the prompt goes in `text` (max 1024 characters) and the button label is fixed by WhatsApp. The recipient's answer arrives as an inbound `location` message whose `content.replyToMessageId` is the ID of the request.\n\n`request_contact_info` asks the recipient to share their phone number and is WhatsApp-only. Like `location_request` it takes no `content` object — the prompt goes in `text` (max 1024 characters) and WhatsApp renders a fixed **Share Contact Info** button. The answer arrives as an inbound `contact` message. Use it to recover the phone number of a contact who adopted a WhatsApp username and is only known by their business-scoped user ID (BSUID); when they share it, Zavu automatically links the phone number to that contact.",
        "enum": [
          "text",
          "image",
          "video",
          "audio",
          "document",
          "sticker",
          "location",
          "contact",
          "buttons",
          "list",
          "cta_url",
          "request_contact_info",
          "location_request",
          "reaction",
          "template"
        ]
      },
      "MessageContent": {
        "type": "object",
        "description": "Content for non-text message types (WhatsApp and Telegram).",
        "properties": {
          "mediaUrl": {
            "type": "string",
            "description": "URL of the media file (for image, video, audio, document, sticker).",
            "example": "https://example.com/image.jpg"
          },
          "mediaId": {
            "type": "string",
            "description": "WhatsApp media ID if already uploaded."
          },
          "mimeType": {
            "type": "string",
            "description": "MIME type of the media.",
            "example": "image/jpeg"
          },
          "filename": {
            "type": "string",
            "description": "Filename for documents.",
            "example": "invoice.pdf"
          },
          "latitude": {
            "type": "number",
            "description": "Latitude for location messages."
          },
          "longitude": {
            "type": "number",
            "description": "Longitude for location messages."
          },
          "locationName": {
            "type": "string",
            "description": "Name of the location."
          },
          "locationAddress": {
            "type": "string",
            "description": "Address of the location."
          },
          "contacts": {
            "type": "array",
            "description": "Contact cards for contact messages.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "phones": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "buttons": {
            "type": "array",
            "description": "Interactive buttons (max 3).",
            "maxItems": 3,
            "items": {
              "type": "object",
              "required": [
                "id",
                "title"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "maxLength": 256
                },
                "title": {
                  "type": "string",
                  "maxLength": 20
                }
              }
            }
          },
          "listButton": {
            "type": "string",
            "description": "Button text for list messages.",
            "maxLength": 20
          },
          "sections": {
            "type": "array",
            "description": "Sections for list messages.",
            "items": {
              "type": "object",
              "required": [
                "title",
                "rows"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "rows": {
                  "type": "array",
                  "maxItems": 10,
                  "items": {
                    "type": "object",
                    "required": [
                      "id",
                      "title"
                    ],
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string",
                        "maxLength": 24
                      },
                      "description": {
                        "type": "string",
                        "maxLength": 72
                      }
                    }
                  }
                }
              }
            }
          },
          "ctaDisplayText": {
            "type": "string",
            "description": "Button label for cta_url messages.",
            "maxLength": 20,
            "example": "See Dates"
          },
          "ctaUrl": {
            "type": "string",
            "format": "uri",
            "description": "Destination URL opened in the device's default browser when the button is tapped. Used with messageType=cta_url. WhatsApp requires HTTPS in production.",
            "example": "https://example.com/schedule"
          },
          "ctaHeaderType": {
            "type": "string",
            "description": "Optional header type for cta_url messages.",
            "enum": [
              "text",
              "image",
              "video",
              "document"
            ]
          },
          "ctaHeaderText": {
            "type": "string",
            "description": "Header text when ctaHeaderType is 'text'.",
            "maxLength": 60
          },
          "ctaHeaderMediaUrl": {
            "type": "string",
            "format": "uri",
            "description": "Public HTTPS URL of the header media when ctaHeaderType is 'image', 'video', or 'document'. WhatsApp fetches this URL — it must be publicly reachable and return the declared content type."
          },
          "footerText": {
            "type": "string",
            "description": "Optional footer text for cta_url messages.",
            "maxLength": 60,
            "example": "Dates subject to change."
          },
          "emoji": {
            "type": "string",
            "description": "Emoji for reaction messages."
          },
          "reactToMessageId": {
            "type": "string",
            "description": "Message ID to react to."
          },
          "replyToMessageId": {
            "type": "string",
            "description": "Zavu message ID of the quoted message this message replies to. Present on inbound messages that quote an earlier message. Omitted when the quoted message is not found in Zavu (e.g. an old or unknown message) — use replyToProviderMessageId in that case."
          },
          "replyToProviderMessageId": {
            "type": "string",
            "description": "Provider message ID (WhatsApp WAMID) of the quoted message. Present whenever an inbound message is a reply, even if the quoted message is not stored in Zavu."
          },
          "replyToFrom": {
            "type": "string",
            "description": "Sender of the quoted message (phone number in E.164 format)."
          },
          "replyToText": {
            "type": "string",
            "description": "Truncated snippet of the quoted message's text, for display. Empty when the quoted message has no text (e.g. media)."
          },
          "replyToMessageType": {
            "type": "string",
            "description": "Type of the quoted message (text, image, video, etc.)."
          },
          "templateId": {
            "type": "string",
            "description": "Template ID for template messages."
          },
          "templateVariables": {
            "type": "object",
            "description": "Variables for body placeholders. Key them to match the template body: by position (`1`, `2`, ...) for positional templates, or by name (e.g. `customer_name`) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Named keys also resolve a named text-header variable. Do not mix positional and named keys in the same request.",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "1": "John",
              "2": "ORD-12345"
            }
          },
          "templateButtonVariables": {
            "type": "object",
            "description": "Variables for dynamic button placeholders (URL buttons and OTP buttons). Keys are the button index (0, 1, 2) in the template's `buttons` array — not the placeholder name. Values substitute the `{{1}}` placeholder inside that button's URL.\n\n**WhatsApp constraints:**\n- URL buttons only accept `{{1}}` — positional, numeric, no whitespace, no name. Named placeholders like `{{token}}` are stored as literal URL text by Meta and cannot be substituted.\n- At most one placeholder per URL button.\n- A template may have at most three buttons.\n- Static URL buttons (no placeholder) and `quick_reply` buttons are not included here.",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "0": "abc-report-token"
            }
          },
          "templateHeaderVariables": {
            "type": "object",
            "description": "Value for a text-header variable, keyed by `1` (WhatsApp text headers allow at most one variable). Optional override. If omitted, Zavu resolves the header from `templateVariables` using the header placeholder's name (e.g. `novios`). Static text headers need no value.",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "1": "Jorge y Laura"
            }
          }
        }
      },
      "EmailAttachmentInput": {
        "type": "object",
        "description": "Email attachment. Provide either `content` (base64) or `path` (URL), not both.",
        "required": [
          "filename"
        ],
        "properties": {
          "filename": {
            "type": "string",
            "description": "Name of the attached file.",
            "maxLength": 255,
            "example": "invoice.pdf"
          },
          "content": {
            "type": "string",
            "description": "Content of the attached file as a Base64-encoded string."
          },
          "path": {
            "type": "string",
            "format": "uri",
            "description": "URL where the attachment file is hosted. The server will fetch the file."
          },
          "content_type": {
            "type": "string",
            "description": "MIME type of the attachment. If not set, will be derived from the filename.",
            "example": "application/pdf"
          },
          "content_id": {
            "type": "string",
            "description": "Content ID for inline images. Reference in HTML as `<img src=\"cid:your_content_id\">`.",
            "maxLength": 100,
            "example": "logo"
          }
        }
      },
      "MessageRequest": {
        "type": "object",
        "description": "Request body to send a message.",
        "required": [
          "to"
        ],
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient phone number in E.164 format, email address, WhatsApp business-scoped user ID (BSUID, e.g. `US.13491208655302741918`), or numeric chat ID (for Telegram/Instagram/Messenger). A BSUID is routed to WhatsApp and sent via the `recipient` field; use it to message a contact who adopted a username and whose phone number is hidden.",
            "example": "+56912345678"
          },
          "channel": {
            "$ref": "#/components/schemas/Channel",
            "description": "Delivery channel. Use 'auto' for intelligent routing. If omitted, channel is auto-selected based on sender capabilities and recipient type. For email recipients, defaults to 'email'.",
            "default": "auto"
          },
          "messageType": {
            "$ref": "#/components/schemas/MessageType",
            "description": "Type of message. Defaults to 'text'.",
            "default": "text"
          },
          "text": {
            "type": "string",
            "description": "Text body for text messages or caption for media messages.",
            "example": "Your verification code is 123456."
          },
          "content": {
            "$ref": "#/components/schemas/MessageContent",
            "description": "Additional content for non-text message types."
          },
          "subject": {
            "type": "string",
            "description": "Email subject line. Required when channel is 'email' or recipient is an email address.",
            "maxLength": 998,
            "example": "Your order confirmation"
          },
          "htmlBody": {
            "type": "string",
            "description": "HTML body for email messages. If provided, email will be sent as multipart with both text and HTML."
          },
          "replyTo": {
            "type": "string",
            "format": "email",
            "description": "Reply-To email address for email messages.",
            "example": "support@example.com"
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Optional idempotency key to avoid duplicate sends.",
            "example": "msg_01HZY4ZP7VQY2J3BRW7Z6G0QGE"
          },
          "metadata": {
            "type": "object",
            "description": "Arbitrary metadata to associate with the message.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "fallbackEnabled": {
            "type": "boolean",
            "description": "Whether to enable automatic fallback to SMS if WhatsApp fails. Defaults to true.",
            "default": true
          },
          "voiceLanguage": {
            "type": "string",
            "description": "Language code for voice text-to-speech (e.g., 'en-US', 'es-ES', 'pt-BR'). If omitted, language is auto-detected from recipient's country code.",
            "example": "es-ES"
          },
          "attachments": {
            "type": "array",
            "description": "Email attachments. Only supported when channel is 'email'. Maximum 40MB total size.",
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/EmailAttachmentInput"
            }
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "to",
          "status",
          "channel",
          "messageType",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "jd7x2k3m4n5p6q7r8s9t0"
          },
          "to": {
            "type": "string",
            "example": "+56912345678"
          },
          "from": {
            "type": "string",
            "example": "+13125551212"
          },
          "senderId": {
            "type": "string",
            "example": "sender_12345"
          },
          "channel": {
            "$ref": "#/components/schemas/Channel"
          },
          "messageType": {
            "$ref": "#/components/schemas/MessageType"
          },
          "status": {
            "$ref": "#/components/schemas/MessageStatus"
          },
          "text": {
            "type": "string",
            "description": "Text content or caption."
          },
          "content": {
            "$ref": "#/components/schemas/MessageContent"
          },
          "conversationId": {
            "type": "string",
            "description": "ID of the conversation (inbox thread) this message belongs to. Use it to build a direct dashboard link: `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`. Omitted only on legacy messages created before conversation threading.",
            "example": "js723987cyghwqxxaxcf590qd18axd95"
          },
          "providerMessageId": {
            "type": "string",
            "description": "Message ID from the delivery provider."
          },
          "errorCode": {
            "type": "string",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "cost": {
            "type": "number",
            "nullable": true,
            "description": "Zavu platform charge in USD for this message. Messaging is billed against your plan's monthly limits plus usage-based overage."
          },
          "costProvider": {
            "type": "number",
            "nullable": true,
            "description": "Carrier and delivery cost in USD."
          },
          "costTotal": {
            "type": "number",
            "nullable": true,
            "description": "Total cost in USD (platform charge + delivery cost)."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MessageResponse": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "$ref": "#/components/schemas/Message"
          }
        }
      },
      "MessageAttachment": {
        "type": "object",
        "description": "A stored file attachment for an email message (inbound or outbound).",
        "required": [
          "id",
          "filename",
          "mimeType",
          "size",
          "contentId",
          "isInline",
          "downloadUrl",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "jd7x2k3m4n5p6q7r8s9t0"
          },
          "filename": {
            "type": "string",
            "example": "invoice.pdf"
          },
          "mimeType": {
            "type": "string",
            "description": "MIME type of the attachment.",
            "example": "application/pdf"
          },
          "size": {
            "type": "integer",
            "description": "Size of the attachment in bytes.",
            "example": 102400
          },
          "contentId": {
            "type": "string",
            "nullable": true,
            "description": "Content-ID for inline attachments (referenced in the HTML body as `cid:<contentId>`). Null for regular attachments.",
            "example": "logo"
          },
          "isInline": {
            "type": "boolean",
            "description": "Whether the attachment is inline (embedded in the HTML body) rather than a regular attachment."
          },
          "downloadUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Short-lived signed URL to download the attachment bytes. Freshly generated on each request and expires; do not cache it. Null if the stored file is no longer available."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MessageAttachmentsResponse": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MessageAttachment"
            }
          }
        }
      },
      "WhatsAppCategory": {
        "type": "string",
        "description": "WhatsApp template category.",
        "enum": [
          "UTILITY",
          "MARKETING",
          "AUTHENTICATION"
        ]
      },
      "Template": {
        "type": "object",
        "required": [
          "id",
          "name",
          "language",
          "body",
          "category"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "Template name. For WhatsApp, must match the approved template name in Meta.",
            "example": "order_confirmation"
          },
          "language": {
            "type": "string",
            "description": "Language code.",
            "example": "en"
          },
          "body": {
            "type": "string",
            "description": "Default template body with variables: positional ({{1}}, {{2}}) or named ({{customer_name}}, {{contact.first_name}}). Templates created in Zavu are submitted to Meta as positional; templates imported from a WhatsApp Business Account keep their original format (named or positional). Used when no channel-specific body is set.",
            "example": "Hi {{1}}, your order {{2}} has shipped."
          },
          "smsBody": {
            "type": "string",
            "description": "Channel-specific body for SMS messages. Falls back to `body` if not set."
          },
          "telegramBody": {
            "type": "string",
            "description": "Channel-specific body for Telegram messages. Falls back to `body` if not set."
          },
          "instagramBody": {
            "type": "string",
            "description": "Channel-specific body for Instagram messages. Falls back to `body` if not set."
          },
          "category": {
            "$ref": "#/components/schemas/WhatsAppCategory"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "approved",
              "rejected"
            ],
            "default": "draft"
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of variable names for documentation."
          },
          "headerType": {
            "type": "string",
            "description": "Type of header (text, image, video, document)."
          },
          "headerContent": {
            "type": "string",
            "description": "Header content (text or media URL)."
          },
          "footer": {
            "type": "string",
            "description": "Footer text for the template."
          },
          "buttons": {
            "type": "array",
            "description": "Template buttons.",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "quick_reply",
                    "url",
                    "phone",
                    "otp",
                    "request_contact_info"
                  ]
                },
                "text": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "example": {
                  "type": "string",
                  "description": "Sample value used to substitute `{{1}}` in the URL when submitting the template to Meta for review. Only present for dynamic URL buttons."
                },
                "phoneNumber": {
                  "type": "string"
                },
                "otpType": {
                  "type": "string",
                  "enum": [
                    "COPY_CODE",
                    "ONE_TAP"
                  ],
                  "description": "OTP button type. Required when type is 'otp'."
                },
                "packageName": {
                  "type": "string",
                  "description": "Android package name. Required for ONE_TAP buttons."
                },
                "signatureHash": {
                  "type": "string",
                  "description": "Android app signature hash. Required for ONE_TAP buttons."
                }
              }
            }
          },
          "addSecurityRecommendation": {
            "type": "boolean",
            "description": "Add 'Do not share this code' disclaimer. Only for AUTHENTICATION templates."
          },
          "codeExpirationMinutes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 90,
            "description": "Code expiration time in minutes. Only for AUTHENTICATION templates."
          },
          "whatsapp": {
            "type": "object",
            "description": "WhatsApp-specific template information.",
            "properties": {
              "templateName": {
                "type": "string",
                "description": "WhatsApp template name."
              },
              "namespace": {
                "type": "string",
                "description": "WhatsApp Business Account namespace."
              },
              "status": {
                "type": "string",
                "description": "WhatsApp approval status."
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TemplateCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "language",
          "body"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "language": {
            "type": "string",
            "default": "en"
          },
          "body": {
            "type": "string",
            "description": "Default template body. Used when no channel-specific body is set."
          },
          "smsBody": {
            "type": "string",
            "description": "Channel-specific body for SMS. Falls back to `body` if not set."
          },
          "telegramBody": {
            "type": "string",
            "description": "Channel-specific body for Telegram. Falls back to `body` if not set."
          },
          "instagramBody": {
            "type": "string",
            "description": "Channel-specific body for Instagram. Falls back to `body` if not set."
          },
          "whatsappCategory": {
            "$ref": "#/components/schemas/WhatsAppCategory"
          },
          "headerType": {
            "type": "string",
            "description": "Type of header for the template.",
            "enum": [
              "text",
              "image",
              "video",
              "document"
            ]
          },
          "headerContent": {
            "type": "string",
            "description": "Header content (text string or media URL)."
          },
          "footer": {
            "type": "string",
            "description": "Footer text for the template.",
            "maxLength": 60
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "buttons": {
            "type": "array",
            "description": "Template buttons (max 3).",
            "maxItems": 3,
            "items": {
              "type": "object",
              "required": [
                "type"
              ],
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "quick_reply",
                    "url",
                    "phone",
                    "otp",
                    "request_contact_info"
                  ],
                  "description": "`request_contact_info` renders a fixed **Share Contact Info** button that asks the recipient to share their phone number — useful when a contact adopted a WhatsApp username and you only know their BSUID. It takes no other fields."
                },
                "text": {
                  "type": "string",
                  "maxLength": 25,
                  "description": "Button label. Required for every type except `request_contact_info`, whose label is fixed by WhatsApp."
                },
                "url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Button destination. Use `{{1}}` exactly once for a dynamic URL (e.g. `https://example.com/orders/{{1}}`); WhatsApp only accepts the strict `{{1}}` form. Static URLs must not contain any `{{...}}` placeholder."
                },
                "example": {
                  "type": "string",
                  "description": "Sample value Meta uses to review templates with a dynamic URL button. Substituted into `{{1}}` of the URL when the template is submitted to Meta. Only meaningful when `url` contains `{{1}}`; ignored for static URLs.",
                  "example": "ORD-12345"
                },
                "phoneNumber": {
                  "type": "string"
                },
                "otpType": {
                  "type": "string",
                  "enum": [
                    "COPY_CODE",
                    "ONE_TAP"
                  ],
                  "description": "Required when type is 'otp'. COPY_CODE shows copy button, ONE_TAP enables Android autofill."
                },
                "packageName": {
                  "type": "string",
                  "description": "Android package name. Required for ONE_TAP buttons."
                },
                "signatureHash": {
                  "type": "string",
                  "description": "Android app signature hash. Required for ONE_TAP buttons."
                }
              }
            }
          },
          "addSecurityRecommendation": {
            "type": "boolean",
            "description": "Add 'Do not share this code' disclaimer. Only for AUTHENTICATION templates."
          },
          "codeExpirationMinutes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 90,
            "description": "Code expiration time in minutes. Only for AUTHENTICATION templates."
          }
        }
      },
      "WebhookEvent": {
        "type": "string",
        "description": "Type of event that triggers the webhook.\n\n**Message lifecycle events:**\n- `message.queued`: Message created and queued for sending. `data.status` = `queued`\n- `message.sent`: Message accepted by the provider. `data.status` = `sent`\n- `message.delivered`: Message delivered to recipient. `data.status` = `delivered`\n- `message.read`: Message was read by the recipient (WhatsApp only). `data.status` = `read`\n- `message.failed`: Message failed to send. `data.status` = `failed`\n\n**Inbound events:**\n- `message.inbound`: New message received from a contact. `data.conversationId` is the inbox thread id (deep-link with `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`); it is `null` while the conversation row is still being created (the first message of a brand-new thread, or several near-simultaneous first messages), where `conversation.new` carries the id instead — `GET /v1/messages/{messageId}` always has it. Reactions are delivered as `message.inbound` with `messageType='reaction'`. When the contact replied to (quoted) an earlier message, `data.content` carries the reply context: `replyToMessageId`, `replyToProviderMessageId`, `replyToFrom`, `replyToText`, and `replyToMessageType`. `data.providerTimestamp` is the provider's original receive time in Unix milliseconds (the moment the channel received the message from the contact — WhatsApp, Telegram, Instagram, Messenger; `null` for SMS and email). Compare it against the top-level `timestamp` (when Zavu dispatched the webhook) to detect and ignore delayed deliveries.\n- `message.unsupported`: Received a message type that is not supported\n\n**Broadcast events:**\n- `broadcast.status_changed`: Broadcast status changed (pending_review, approved, rejected, sending, completed, cancelled)\n\n**Other events:**\n- `conversation.new`: New conversation started with a contact. `data` carries `conversationId` (the inbox thread id — deep-link with `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`), the `phoneNumber` or `email` key, `channel`, `firstMessageId`, `firstMessageText`, and `profileName`.\n- `template.status_changed`: WhatsApp template approval status changed\n\n**Partner events:**\n- `invitation.status_changed`: A partner invitation status changed (pending, in_progress, completed, cancelled, failed). `data` carries `invitationId`, `clientName`, `clientEmail`, `connectionType` (`whatsapp_waba` or `messenger`), `previousStatus`, and `currentStatus`. On `completed` it also carries `senderId` and `connectedAccount` (`channel`, `id`, `name`) — the WhatsApp number or Facebook Page that was linked. On `failed` it carries `failureReason`; the invitation link stays usable, so a client can retry it.\n\n**Voice Agent events:**\nFor every voice event, `data` carries `callId`, `direction`, `from`, `to`, `status`, `durationSeconds`, `endReason`, and `transcriptAvailable`. The terminal events (`call.completed`, `call.failed`) additionally carry `cost` — what the call was billed, in USD, combining telephony and the managed voice pipeline — and `currency`. They are dispatched after the call is charged, so `cost` is populated rather than zero; telephony can still be settling on an outbound call, in which case `GET /v1/calls/{callId}` holds the reconciled figure.\n- `call.initiated`: An outbound call was created and is dialing, or an inbound call was received. `data.status` = `ringing`\n- `call.answered`: The call was answered and the voice agent is connected. `data.status` = `in_progress`\n- `call.completed`: The call ended after a conversation. `data.status` = `completed`; `durationSeconds` and `endReason` describe how it ended, and `transcriptAvailable` indicates whether a transcript can be fetched.\n- `call.failed`: The call could not be completed (busy, no answer, canceled, or an error). `data.status` is the terminal status and `endReason` explains the cause.\n\n**Custom domain events:**\n- `domain.verified`: A custom email domain passed verification (DKIM, and SPF/DMARC/MAIL FROM if enhanced records are enabled)\n- `domain.failed`: A custom email domain failed verification or is partially verified",
        "enum": [
          "message.queued",
          "message.sent",
          "message.delivered",
          "message.read",
          "message.status",
          "message.failed",
          "message.inbound",
          "message.unsupported",
          "broadcast.status_changed",
          "conversation.new",
          "template.status_changed",
          "invitation.status_changed",
          "call.initiated",
          "call.answered",
          "call.completed",
          "call.failed",
          "domain.verified",
          "domain.failed"
        ]
      },
      "WebhookPayload": {
        "type": "object",
        "description": "Webhook payload structure sent to your endpoint.",
        "required": [
          "id",
          "type",
          "timestamp",
          "senderId",
          "projectId",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique event identifier.",
            "example": "evt_1736850000000_abc123"
          },
          "type": {
            "$ref": "#/components/schemas/WebhookEvent"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix timestamp in milliseconds when the event was created.",
            "example": 1736850000000
          },
          "senderId": {
            "type": "string",
            "description": "ID of the sender associated with this event.",
            "example": "jx7abc123def456"
          },
          "projectId": {
            "type": "string",
            "description": "ID of the project.",
            "example": "jx7xyz789ghi012"
          },
          "data": {
            "type": "object",
            "description": "Event-specific data. For message events, contains messageId, to, channel, status, errorCode, and errorMessage."
          }
        }
      },
      "WebhookMessageData": {
        "type": "object",
        "description": "Data payload for message webhook events (queued, sent, delivered, failed, inbound).",
        "required": [
          "messageId",
          "to",
          "channel",
          "status"
        ],
        "properties": {
          "messageId": {
            "type": "string",
            "description": "ID of the message.",
            "example": "jx7744x3wckc9cwy0j9c8g6v0h7z7shs"
          },
          "to": {
            "type": "string",
            "description": "Recipient phone number or email. On `message.inbound` this is your own number (the message's destination).",
            "example": "+56912345678"
          },
          "from": {
            "type": "string",
            "description": "Sender of the message. Present on `message.inbound`: the contact who sent the message.",
            "example": "+14155551234"
          },
          "channel": {
            "$ref": "#/components/schemas/Channel"
          },
          "status": {
            "$ref": "#/components/schemas/MessageStatus"
          },
          "messageType": {
            "$ref": "#/components/schemas/MessageType",
            "description": "Type of the message. Present on `message.inbound`."
          },
          "conversationId": {
            "type": "string",
            "nullable": true,
            "description": "ID of the conversation (inbox thread) this message belongs to. Present on `message.inbound`. Use it to deep-link to the dashboard inbox: `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`. It is `null` while the conversation row is still being created: on the first inbound message of a brand-new thread, and — if several messages from a never-seen address arrive near-simultaneously — on each of those, even though only one `conversation.new` is emitted. Recover the id from the `conversation.new` event, or fetch it any time via `GET /v1/messages/{messageId}`, whose `conversationId` is always populated.",
            "example": "js723987cyghwqxxaxcf590qd18axd95"
          },
          "text": {
            "type": "string",
            "description": "Text body or media caption. Present on `message.inbound` when the message has text."
          },
          "errorCode": {
            "type": "string",
            "nullable": true,
            "description": "Error code if the message failed."
          },
          "errorMessage": {
            "type": "string",
            "nullable": true,
            "description": "Error message if the message failed."
          },
          "providerTimestamp": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "The provider's original receive time in Unix milliseconds (when the channel received the message from the contact). Present on `message.inbound` for channels that report it (WhatsApp, Telegram, Instagram, Messenger); null for SMS and email."
          }
        }
      },
      "SenderWebhook": {
        "type": "object",
        "description": "Webhook configuration for the sender.",
        "required": [
          "url",
          "events",
          "active",
          "signatureVersion"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL that will receive webhook events.",
            "example": "https://api.example.com/webhooks/zavu"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEvent"
            },
            "description": "List of events the webhook is subscribed to."
          },
          "secret": {
            "type": "string",
            "description": "Webhook secret for signature verification. Only returned on create or regenerate.",
            "example": "whsec_abc123..."
          },
          "active": {
            "type": "boolean",
            "description": "Whether the webhook is active.",
            "default": true
          },
          "signatureVersion": {
            "$ref": "#/components/schemas/WebhookSignatureVersion"
          }
        }
      },
      "Sender": {
        "type": "object",
        "required": [
          "id",
          "name",
          "phoneNumber"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "sender_12345"
          },
          "name": {
            "type": "string",
            "example": "Primary sender"
          },
          "phoneNumber": {
            "type": "string",
            "description": "Phone number in E.164 format.",
            "example": "+13125551212"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Channels this sender can actually send on right now, computed from its configuration. Empty means the sender cannot send or receive anything yet: a phoneNumber alone does not enable SMS or voice. Check this rather than inferring capability from phoneNumber or emailAddress.",
            "example": [
              "sms",
              "voice"
            ]
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this sender is the project's default.",
            "default": false
          },
          "webhook": {
            "$ref": "#/components/schemas/SenderWebhook"
          },
          "whatsapp": {
            "type": "object",
            "description": "WhatsApp Business Account information. Only present if a WABA is connected.",
            "properties": {
              "phoneNumberId": {
                "type": "string",
                "description": "WhatsApp phone number ID from Meta."
              },
              "displayPhoneNumber": {
                "type": "string",
                "description": "Display phone number.",
                "example": "+14155551234"
              },
              "paymentStatus": {
                "type": "object",
                "description": "Payment configuration status from Meta.",
                "properties": {
                  "setupStatus": {
                    "type": "string",
                    "description": "Payment setup status (COMPLETE, NOT_STARTED, etc.).",
                    "example": "COMPLETE"
                  },
                  "methodStatus": {
                    "type": "string",
                    "description": "Payment method status (VALID, NONE, etc.).",
                    "example": "VALID"
                  },
                  "canSendTemplates": {
                    "type": "boolean",
                    "description": "Whether template messages can be sent. Requires setupStatus=COMPLETE and methodStatus=VALID."
                  }
                }
              }
            }
          },
          "emailAddress": {
            "type": "string",
            "description": "From-address for the email channel, if configured.",
            "example": "noreply@yourdomain.com"
          },
          "emailReceivingEnabled": {
            "type": "boolean",
            "description": "Whether inbound email receiving is enabled for this sender.",
            "default": false
          },
          "emailCatchAllEnabled": {
            "type": "boolean",
            "description": "Whether catch-all receiving is enabled. When true (and emailReceivingEnabled is true), this sender receives email addressed to any local part at its domain, not just its own address. The original recipient is delivered in the message.inbound webhook's data.to.",
            "default": false
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SenderCreateRequest": {
        "type": "object",
        "description": "Create a sender. Provide `phoneNumber` for an SMS/WhatsApp sender, `emailAddress` (with a verified email domain) for an email sender, or `enableSmsOneway: true` for a zero-setup one-way SMS sender — at least one is required.",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string",
            "description": "Phone number in E.164 format, and it must be a number your project already owns (see `GET /v1/phone-numbers`). The number is routed to the sender as part of this call, which is what turns the SMS channel on. Passing a number the project does not own, or one already attached to another sender, returns 400 rather than creating a sender that cannot send. Omit for an email-only sender."
          },
          "enableVoice": {
            "type": "boolean",
            "description": "Let this sender place and answer phone calls. Requires `phoneNumber`; enabling it without one returns 400. Check the `channels` array on the response to confirm `voice` is on.",
            "default": false
          },
          "enableSmsOneway": {
            "type": "boolean",
            "description": "Enable the one-way SMS channel (`sms_oneway`). Needs nothing else — no phone number, no credential — so it is the fastest way to get a sender that can send. Recipients cannot reply. Confirm with `sms_oneway` in the `channels` array on the response.",
            "default": false
          },
          "setAsDefault": {
            "type": "boolean",
            "default": false
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL for webhook events."
          },
          "webhookEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEvent"
            },
            "description": "Events to subscribe to."
          },
          "emailAddress": {
            "type": "string",
            "format": "email",
            "description": "From-address for the email channel (e.g. noreply@yourdomain.com). The address's domain must be a verified email domain in your project. Setting this attaches the email channel to the sender.",
            "example": "noreply@yourdomain.com"
          },
          "emailDomainId": {
            "type": "string",
            "description": "ID of the verified email domain to attach. Optional — resolved from `emailAddress`'s domain when omitted."
          },
          "emailFromName": {
            "type": "string",
            "maxLength": 100,
            "description": "Display name shown in the recipient's inbox for the email channel."
          },
          "emailReceivingEnabled": {
            "type": "boolean",
            "description": "Enable inbound email receiving on this sender. Requires a verified MX record on the domain; ignored otherwise."
          },
          "webhookSignatureVersion": {
            "allOf": [
              {
                "$ref": "#/components/schemas/WebhookSignatureVersion"
              }
            ],
            "description": "Signature scheme for this sender's webhook. Defaults to `v2`, which is correct for a new receiver. Pass `v1+v2` when this sender points at an endpoint that already serves an older sender still verifying `v1`."
          }
        }
      },
      "SenderUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "enableVoice": {
            "type": "boolean",
            "description": "Turn the voice channel on or off. The sender must already have a phone number provisioned for calls; enabling it otherwise returns 400 instead of storing a flag that changes nothing. Confirm with the `channels` array on the response."
          },
          "enableSmsOneway": {
            "type": "boolean",
            "description": "Turn the one-way SMS channel on or off. Enabling needs nothing else and takes effect immediately; disabling removes the channel from the sender. Confirm with the `channels` array on the response."
          },
          "setAsDefault": {
            "type": "boolean"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "HTTPS URL for webhook events. Set to null to remove webhook."
          },
          "webhookEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEvent"
            },
            "description": "Events to subscribe to."
          },
          "webhookActive": {
            "type": "boolean",
            "description": "Whether the webhook is active."
          },
          "emailReceivingEnabled": {
            "type": "boolean",
            "description": "Enable or disable inbound email receiving for this sender."
          },
          "emailCatchAllEnabled": {
            "type": "boolean",
            "description": "Enable or disable domain catch-all. When enabled (with emailReceivingEnabled true), this sender receives email for any address at its domain. Ignored (treated as false) if receiving is not enabled."
          },
          "emailAddress": {
            "type": "string",
            "format": "email",
            "description": "Attach or change the sender's email from-address (e.g. noreply@yourdomain.com). The domain must be a verified email domain in your project.",
            "example": "noreply@yourdomain.com"
          },
          "emailDomainId": {
            "type": "string",
            "description": "ID of the verified email domain to attach. Optional — resolved from `emailAddress`'s domain when omitted."
          },
          "emailFromName": {
            "type": "string",
            "maxLength": 100,
            "description": "Display name shown in the recipient's inbox for the email channel."
          },
          "webhookSignatureVersion": {
            "allOf": [
              {
                "$ref": "#/components/schemas/WebhookSignatureVersion"
              }
            ],
            "description": "Move this webhook between signature schemes. `v1` -> `v2` directly returns `400`; go through `v1+v2` first. See https://docs.zavu.dev/guides/receiving-messages/signature-migration"
          }
        }
      },
      "WebhookSecretResponse": {
        "type": "object",
        "required": [
          "secret"
        ],
        "properties": {
          "secret": {
            "type": "string",
            "description": "The new webhook secret.",
            "example": "whsec_abc123..."
          }
        }
      },
      "ContactChannel": {
        "type": "object",
        "description": "A communication channel for a contact.",
        "required": [
          "id",
          "channel",
          "identifier",
          "isPrimary",
          "verified",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "sms",
              "whatsapp",
              "email",
              "telegram",
              "instagram",
              "messenger",
              "voice"
            ],
            "description": "Channel type."
          },
          "identifier": {
            "type": "string",
            "description": "Channel identifier (phone number or email address).",
            "example": "+14155551234"
          },
          "countryCode": {
            "type": "string",
            "description": "ISO country code for phone numbers.",
            "example": "US"
          },
          "label": {
            "type": "string",
            "description": "Optional label for the channel.",
            "example": "work"
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether this is the primary channel for its type."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether this channel has been verified."
          },
          "metrics": {
            "type": "object",
            "description": "Delivery metrics for this channel.",
            "properties": {
              "successCount": {
                "type": "integer"
              },
              "failureCount": {
                "type": "integer"
              },
              "totalAttempts": {
                "type": "integer"
              },
              "avgDeliveryTimeMs": {
                "type": "number"
              },
              "lastSuccessAt": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "lastInboundAt": {
            "type": "string",
            "format": "date-time",
            "description": "Last time a message was received on this channel."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Contact": {
        "type": "object",
        "required": [
          "id",
          "availableChannels",
          "verified",
          "metadata",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "displayName": {
            "type": "string",
            "description": "Display name for the contact.",
            "example": "John Doe"
          },
          "phoneNumber": {
            "type": "string",
            "description": "DEPRECATED: Use primaryPhone instead. Primary phone number in E.164 format.",
            "example": "+56912345678"
          },
          "primaryPhone": {
            "type": "string",
            "description": "Primary phone number in E.164 format.",
            "example": "+56912345678"
          },
          "primaryEmail": {
            "type": "string",
            "format": "email",
            "description": "Primary email address.",
            "example": "john@example.com"
          },
          "countryCode": {
            "type": "string",
            "example": "CL"
          },
          "profileName": {
            "type": "string",
            "nullable": true,
            "description": "Contact's WhatsApp profile name. Only available for WhatsApp contacts.",
            "example": "John Doe"
          },
          "availableChannels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of available messaging channels for this contact."
          },
          "defaultChannel": {
            "type": "string",
            "enum": [
              "sms",
              "whatsapp",
              "telegram",
              "email",
              "instagram",
              "messenger",
              "voice"
            ],
            "description": "Preferred channel for this contact."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether this contact has been verified."
          },
          "channels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactChannel"
            },
            "description": "All communication channels for this contact."
          },
          "suggestedMergeWith": {
            "type": "string",
            "description": "ID of a contact suggested for merging."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactUpdateRequest": {
        "type": "object",
        "properties": {
          "defaultChannel": {
            "type": "string",
            "enum": [
              "sms",
              "whatsapp",
              "telegram",
              "email",
              "instagram",
              "messenger",
              "voice"
            ],
            "nullable": true,
            "description": "Preferred channel for this contact. Set to null to clear."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "ContactChannelInput": {
        "type": "object",
        "description": "Input for creating a contact channel.",
        "required": [
          "channel",
          "identifier"
        ],
        "properties": {
          "channel": {
            "type": "string",
            "enum": [
              "sms",
              "whatsapp",
              "email",
              "telegram",
              "instagram",
              "messenger",
              "voice"
            ],
            "description": "Channel type."
          },
          "identifier": {
            "type": "string",
            "description": "Channel identifier (phone number in E.164 format or email address).",
            "example": "+14155551234"
          },
          "countryCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO country code for phone numbers.",
            "example": "US"
          },
          "label": {
            "type": "string",
            "maxLength": 50,
            "description": "Optional label for the channel.",
            "example": "work"
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether this should be the primary channel for its type.",
            "default": false
          }
        }
      },
      "ContactCreateRequest": {
        "type": "object",
        "description": "Request body to create a contact with channels.",
        "required": [
          "channels"
        ],
        "properties": {
          "displayName": {
            "type": "string",
            "maxLength": 200,
            "description": "Display name for the contact.",
            "example": "John Doe"
          },
          "channels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactChannelInput"
            },
            "minItems": 1,
            "maxItems": 20,
            "description": "Communication channels for the contact."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Arbitrary metadata to associate with the contact."
          }
        }
      },
      "AddChannelRequest": {
        "type": "object",
        "description": "Request body to add a channel to a contact.",
        "required": [
          "channel",
          "identifier"
        ],
        "properties": {
          "channel": {
            "type": "string",
            "enum": [
              "sms",
              "whatsapp",
              "email",
              "telegram",
              "instagram",
              "messenger",
              "voice"
            ],
            "description": "Channel type."
          },
          "identifier": {
            "type": "string",
            "description": "Channel identifier (phone number in E.164 format or email address).",
            "example": "+14155551234"
          },
          "countryCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO country code for phone numbers.",
            "example": "US"
          },
          "label": {
            "type": "string",
            "maxLength": 50,
            "description": "Optional label for the channel.",
            "example": "work"
          },
          "isPrimary": {
            "type": "boolean",
            "description": "Whether this should be the primary channel for its type.",
            "default": false
          }
        }
      },
      "UpdateChannelRequest": {
        "type": "object",
        "description": "Request body to update a channel.",
        "properties": {
          "label": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Optional label for the channel. Set to null to clear."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether the channel is verified."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "MergeContactsRequest": {
        "type": "object",
        "description": "Request body to merge contacts.",
        "required": [
          "sourceContactId"
        ],
        "properties": {
          "sourceContactId": {
            "type": "string",
            "description": "ID of the contact to merge into the target contact. The source contact will be marked as merged."
          }
        }
      },
      "ContactChannelResponse": {
        "type": "object",
        "required": [
          "channel"
        ],
        "properties": {
          "channel": {
            "$ref": "#/components/schemas/ContactChannel"
          }
        }
      },
      "Conversation": {
        "type": "object",
        "description": "An inbox thread with one contact. A conversation groups every message exchanged with that contact across channels, so a contact who writes on WhatsApp and later by email stays in one thread.",
        "required": [
          "id",
          "contactIdentifier",
          "channels",
          "lastMessage",
          "messageCount",
          "unreadCount",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "js723987cyghwqxxaxcf590qd18axd95"
          },
          "contactId": {
            "type": "string",
            "description": "ID of the contact this thread belongs to. Absent on group threads and on threads whose contact has not been resolved yet."
          },
          "contactIdentifier": {
            "type": "string",
            "description": "The key this thread is filed under: a phone number in E.164, a WhatsApp business-scoped user ID (BSUID), a numeric chat ID (Telegram/Instagram/Messenger), or a group JID. It is not always a phone number, so do not parse it as one.",
            "example": "+56912345678"
          },
          "email": {
            "type": "string",
            "description": "Email address of the thread, when the contact was reached by email."
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every channel this thread has carried messages on.",
            "example": [
              "whatsapp",
              "sms"
            ]
          },
          "lastMessage": {
            "type": "object",
            "description": "Denormalized preview of the most recent message, so a thread list needs no extra fetch.",
            "required": [
              "id",
              "text",
              "channel",
              "direction",
              "at"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "text": {
                "type": "string",
                "description": "Text or caption. Empty when the last message carried no text (e.g. media)."
              },
              "channel": {
                "$ref": "#/components/schemas/Channel"
              },
              "direction": {
                "type": "string",
                "enum": [
                  "inbound",
                  "outbound"
                ]
              },
              "at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "senderId": {
            "type": "string",
            "description": "Sender that last handled this thread. Use it as the `Zavu-Sender` header when replying so the answer leaves from the same number the contact knows."
          },
          "messageCount": {
            "type": "integer"
          },
          "unreadCount": {
            "type": "integer",
            "description": "Inbound messages not yet marked read. Reset with POST /v1/conversations/{conversationId}/read."
          },
          "whatsapp": {
            "type": "object",
            "description": "WhatsApp identity, present when the contact adopted a username.",
            "properties": {
              "bsuid": {
                "type": "string",
                "description": "Business-scoped user ID. Can be used as `to` when sending."
              },
              "username": {
                "type": "string"
              }
            }
          },
          "group": {
            "type": "object",
            "description": "Present when the thread is a group chat rather than a one-to-one conversation.",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "subject": {
                "type": "string"
              },
              "participantCount": {
                "type": "integer"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConversationResponse": {
        "type": "object",
        "required": [
          "conversation"
        ],
        "properties": {
          "conversation": {
            "$ref": "#/components/schemas/Conversation"
          }
        }
      },
      "PhoneIntrospectionRequest": {
        "type": "object",
        "required": [
          "phoneNumber"
        ],
        "properties": {
          "phoneNumber": {
            "type": "string",
            "example": "+56912345678"
          }
        }
      },
      "LineType": {
        "type": "string",
        "description": "Type of phone line.",
        "enum": [
          "mobile",
          "landline",
          "voip",
          "toll_free",
          "unknown"
        ]
      },
      "Carrier": {
        "type": "object",
        "description": "Carrier information for the phone number.",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Carrier name.",
            "example": "Verizon Wireless"
          },
          "type": {
            "$ref": "#/components/schemas/LineType"
          }
        }
      },
      "PhoneIntrospectionResponse": {
        "type": "object",
        "required": [
          "phoneNumber",
          "countryCode",
          "validNumber"
        ],
        "properties": {
          "phoneNumber": {
            "type": "string"
          },
          "countryCode": {
            "type": "string",
            "example": "CL"
          },
          "validNumber": {
            "type": "boolean"
          },
          "nationalFormat": {
            "type": "string",
            "description": "Phone number in national format.",
            "example": "(312) 945-7420"
          },
          "lineType": {
            "$ref": "#/components/schemas/LineType"
          },
          "carrier": {
            "$ref": "#/components/schemas/Carrier"
          },
          "availableChannels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of available messaging channels for this phone number."
          }
        }
      },
      "EmailIntrospectionRequest": {
        "type": "object",
        "description": "Validate one email (`email`) or a batch (`emails`). At most 100 addresses per request across both fields.",
        "properties": {
          "email": {
            "type": "string",
            "description": "Single email address to validate.",
            "example": "maria@example.com"
          },
          "emails": {
            "type": "array",
            "description": "Batch of email addresses to validate (max 100).",
            "maxItems": 100,
            "items": {
              "type": "string"
            },
            "example": [
              "maria@example.com",
              "info@deaddomain.example"
            ]
          }
        }
      },
      "EmailValidationResult": {
        "type": "object",
        "required": [
          "email",
          "normalized",
          "domain",
          "verdict",
          "reasons"
        ],
        "properties": {
          "email": {
            "type": "string",
            "description": "The address exactly as submitted."
          },
          "normalized": {
            "type": "string",
            "nullable": true,
            "description": "Lowercased, trimmed form of the address. Null when the syntax is invalid."
          },
          "domain": {
            "type": "string",
            "nullable": true,
            "description": "Domain part of the address. Null when the syntax is invalid."
          },
          "verdict": {
            "type": "string",
            "description": "Validation verdict.\n- `deliverable`: nothing suggests the address will bounce.\n- `risky`: sendable, but a signal predicts elevated bounce/complaint odds (role address, disposable domain, MX-less domain, prior soft bounce).\n- `undeliverable`: will bounce or is blocked (invalid syntax, dead domain, or the address is on your suppression list after a hard bounce/complaint).",
            "enum": [
              "deliverable",
              "risky",
              "undeliverable"
            ]
          },
          "reasons": {
            "type": "array",
            "description": "Signals behind the verdict. Empty for a clean `deliverable` address.",
            "items": {
              "type": "string",
              "enum": [
                "invalid_syntax",
                "domain_not_found",
                "domain_no_mx",
                "disposable_domain",
                "role_address",
                "suppressed_hard_bounce",
                "suppressed_soft_bounce",
                "suppressed_complaint",
                "suppressed_manual",
                "suppressed_unsubscribe"
              ]
            }
          }
        }
      },
      "EmailIntrospectionResponse": {
        "type": "object",
        "required": [
          "results",
          "summary"
        ],
        "properties": {
          "results": {
            "type": "array",
            "description": "One result per submitted address, in the same order.",
            "items": {
              "$ref": "#/components/schemas/EmailValidationResult"
            }
          },
          "summary": {
            "type": "object",
            "required": [
              "total",
              "deliverable",
              "risky",
              "undeliverable"
            ],
            "properties": {
              "total": {
                "type": "integer"
              },
              "deliverable": {
                "type": "integer"
              },
              "risky": {
                "type": "integer"
              },
              "undeliverable": {
                "type": "integer"
              }
            }
          }
        }
      },
      "InteractiveButton": {
        "type": "object",
        "required": [
          "id",
          "title"
        ],
        "properties": {
          "id": {
            "type": "string",
            "maxLength": 256,
            "description": "Unique button identifier returned in webhook when clicked."
          },
          "title": {
            "type": "string",
            "maxLength": 20,
            "description": "Button text displayed to user."
          }
        }
      },
      "ListSection": {
        "type": "object",
        "required": [
          "title",
          "rows"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Section title."
          },
          "rows": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/ListRow"
            }
          }
        }
      },
      "ListRow": {
        "type": "object",
        "required": [
          "id",
          "title"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique row identifier."
          },
          "title": {
            "type": "string",
            "maxLength": 24,
            "description": "Row title."
          },
          "description": {
            "type": "string",
            "maxLength": 72,
            "description": "Optional row description."
          }
        }
      },
      "ContactCard": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "object",
            "required": [
              "formatted_name"
            ],
            "properties": {
              "formatted_name": {
                "type": "string"
              },
              "first_name": {
                "type": "string"
              },
              "last_name": {
                "type": "string"
              }
            }
          },
          "phones": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "phone": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "MOBILE",
                    "HOME",
                    "WORK"
                  ]
                }
              }
            }
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "email": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "HOME",
                    "WORK"
                  ]
                }
              }
            }
          }
        }
      },
      "ReactionRequest": {
        "type": "object",
        "required": [
          "emoji"
        ],
        "properties": {
          "emoji": {
            "type": "string",
            "description": "Single emoji character to react with.",
            "example": "👍"
          }
        }
      },
      "BroadcastChannel": {
        "type": "string",
        "description": "Broadcast delivery channel. Use 'smart' for per-contact intelligent routing.",
        "enum": [
          "smart",
          "sms",
          "sms_oneway",
          "whatsapp",
          "telegram",
          "email"
        ]
      },
      "BroadcastStatus": {
        "type": "string",
        "description": "Current status of the broadcast.",
        "enum": [
          "draft",
          "pending_review",
          "approved",
          "rejected",
          "escalated",
          "rejected_final",
          "scheduled",
          "sending",
          "paused",
          "completed",
          "cancelled",
          "failed"
        ]
      },
      "BroadcastContactStatus": {
        "type": "string",
        "description": "Status of a contact within a broadcast.",
        "enum": [
          "pending",
          "queued",
          "sending",
          "delivered",
          "failed",
          "skipped"
        ]
      },
      "BroadcastMessageType": {
        "type": "string",
        "description": "Type of message for broadcast.",
        "enum": [
          "text",
          "image",
          "video",
          "audio",
          "document",
          "template"
        ]
      },
      "BroadcastContent": {
        "type": "object",
        "description": "Content for non-text broadcast message types.",
        "properties": {
          "mediaUrl": {
            "type": "string",
            "description": "URL of the media file."
          },
          "mediaId": {
            "type": "string",
            "description": "Media ID if already uploaded."
          },
          "mimeType": {
            "type": "string",
            "description": "MIME type of the media."
          },
          "filename": {
            "type": "string",
            "description": "Filename for documents."
          },
          "templateId": {
            "type": "string",
            "description": "Template ID for template messages."
          },
          "templateVariables": {
            "type": "object",
            "description": "Default body variables (can be overridden per contact). Key them to match the template body: by position (`1`, `2`, ...) for positional templates, or by name (e.g. `customer_name`) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Do not mix positional and named keys.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "templateButtonVariables": {
            "type": "object",
            "description": "Default button variables for dynamic URL/OTP buttons. Keys are the button index (0, 1, 2). Per-contact values override these.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "templateHeaderVariables": {
            "type": "object",
            "description": "Default value for a text-header variable, keyed by `1` (can be overridden per contact). If omitted, Zavu resolves the header from `templateVariables` by the header placeholder's name.",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "BroadcastCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "channel"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the broadcast campaign.",
            "example": "Black Friday Sale"
          },
          "channel": {
            "$ref": "#/components/schemas/BroadcastChannel"
          },
          "messageType": {
            "$ref": "#/components/schemas/BroadcastMessageType",
            "default": "text"
          },
          "text": {
            "type": "string",
            "description": "Text content or caption. Supports template variables: {{name}}, {{1}}, etc.",
            "example": "Hi {{name}}, check out our Black Friday deals!"
          },
          "content": {
            "$ref": "#/components/schemas/BroadcastContent"
          },
          "senderId": {
            "type": "string",
            "description": "Sender profile ID. Uses default sender if omitted."
          },
          "emailSubject": {
            "type": "string",
            "description": "Email subject line. Required for email broadcasts."
          },
          "emailHtmlBody": {
            "type": "string",
            "description": "HTML body for email broadcasts."
          },
          "scheduledAt": {
            "type": "string",
            "format": "date-time",
            "description": "Schedule the broadcast for future delivery."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Idempotency key to prevent duplicate broadcasts."
          }
        }
      },
      "BroadcastUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "content": {
            "$ref": "#/components/schemas/BroadcastContent"
          },
          "emailSubject": {
            "type": "string"
          },
          "emailHtmlBody": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "BroadcastContactInput": {
        "type": "object",
        "required": [
          "recipient"
        ],
        "properties": {
          "recipient": {
            "type": "string",
            "description": "Phone number (E.164) or email address.",
            "example": "+14155551234"
          },
          "templateVariables": {
            "type": "object",
            "description": "Per-contact body variables. Key them to match the template body: by position (`1`, `2`, ...) for positional templates, or by name (e.g. `customer_name`) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Do not mix positional and named keys.",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "1": "John",
              "2": "ORD-12345"
            }
          },
          "templateButtonVariables": {
            "type": "object",
            "description": "Per-contact button variables for dynamic URL/OTP buttons. Keys are the button index (0, 1, 2).",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "0": "abc-report-token"
            }
          },
          "templateHeaderVariables": {
            "type": "object",
            "description": "Per-contact value for a text-header variable, keyed by `1`. If omitted, Zavu resolves the header from `templateVariables` by the header placeholder's name.",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "1": "Jorge y Laura"
            }
          }
        }
      },
      "BroadcastContactsAddRequest": {
        "type": "object",
        "required": [
          "contacts"
        ],
        "properties": {
          "contacts": {
            "type": "array",
            "description": "List of contacts to add (max 1000 per request).",
            "maxItems": 1000,
            "items": {
              "$ref": "#/components/schemas/BroadcastContactInput"
            }
          }
        }
      },
      "BroadcastContactsAddResponse": {
        "type": "object",
        "required": [
          "added",
          "duplicates",
          "invalid"
        ],
        "properties": {
          "added": {
            "type": "integer",
            "description": "Number of contacts successfully added."
          },
          "duplicates": {
            "type": "integer",
            "description": "Number of duplicate contacts skipped."
          },
          "invalid": {
            "type": "integer",
            "description": "Number of invalid contacts rejected."
          },
          "errors": {
            "type": "array",
            "description": "Details about invalid contacts.",
            "items": {
              "type": "object",
              "properties": {
                "recipient": {
                  "type": "string"
                },
                "reason": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "BroadcastSendRequest": {
        "type": "object",
        "properties": {
          "scheduledAt": {
            "type": "string",
            "format": "date-time",
            "description": "Schedule for future delivery. Omit to send immediately."
          }
        }
      },
      "BroadcastRescheduleRequest": {
        "type": "object",
        "required": [
          "scheduledAt"
        ],
        "properties": {
          "scheduledAt": {
            "type": "string",
            "format": "date-time",
            "description": "New scheduled time for the broadcast."
          }
        }
      },
      "Broadcast": {
        "type": "object",
        "required": [
          "id",
          "name",
          "status",
          "channel",
          "messageType",
          "totalContacts",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "brd_abc123"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/BroadcastStatus"
          },
          "channel": {
            "$ref": "#/components/schemas/BroadcastChannel"
          },
          "messageType": {
            "$ref": "#/components/schemas/BroadcastMessageType"
          },
          "text": {
            "type": "string"
          },
          "content": {
            "$ref": "#/components/schemas/BroadcastContent"
          },
          "senderId": {
            "type": "string"
          },
          "emailSubject": {
            "type": "string"
          },
          "totalContacts": {
            "type": "integer",
            "description": "Total number of contacts in the broadcast."
          },
          "pendingCount": {
            "type": "integer"
          },
          "sendingCount": {
            "type": "integer"
          },
          "deliveredCount": {
            "type": "integer"
          },
          "failedCount": {
            "type": "integer"
          },
          "estimatedCost": {
            "type": "number",
            "nullable": true,
            "description": "Estimated total cost in USD."
          },
          "reservedAmount": {
            "type": "number",
            "nullable": true,
            "description": "Amount reserved from balance in USD."
          },
          "actualCost": {
            "type": "number",
            "nullable": true,
            "description": "Actual cost so far in USD."
          },
          "scheduledAt": {
            "type": "string",
            "format": "date-time"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "completedAt": {
            "type": "string",
            "format": "date-time"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "reviewResult": {
            "type": "object",
            "nullable": true,
            "description": "AI content review result.",
            "properties": {
              "score": {
                "type": "number",
                "description": "Content safety score from 0.0 to 1.0, where 1.0 is completely safe."
              },
              "categories": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Policy categories violated, if any."
              },
              "reasoning": {
                "type": "string",
                "description": "Explanation of the review decision."
              },
              "reviewedAt": {
                "type": "string",
                "format": "date-time"
              },
              "flaggedContent": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "nullable": true,
                "description": "Problematic text fragments, if any."
              }
            }
          },
          "reviewAttempts": {
            "type": "integer",
            "nullable": true,
            "description": "Number of review attempts (max 3)."
          }
        }
      },
      "BroadcastResponse": {
        "type": "object",
        "required": [
          "broadcast"
        ],
        "properties": {
          "broadcast": {
            "$ref": "#/components/schemas/Broadcast"
          }
        }
      },
      "BroadcastContact": {
        "type": "object",
        "required": [
          "id",
          "recipient",
          "recipientType",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "recipient": {
            "type": "string"
          },
          "recipientType": {
            "type": "string",
            "enum": [
              "phone",
              "email"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/BroadcastContactStatus"
          },
          "templateVariables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "templateButtonVariables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "templateHeaderVariables": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "messageId": {
            "type": "string",
            "description": "Associated message ID after processing."
          },
          "errorCode": {
            "type": "string"
          },
          "errorMessage": {
            "type": "string"
          },
          "cost": {
            "type": "number",
            "nullable": true
          },
          "processedAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BroadcastProgress": {
        "type": "object",
        "required": [
          "broadcastId",
          "status",
          "total",
          "pending",
          "sending",
          "delivered",
          "failed",
          "skipped",
          "percentComplete"
        ],
        "properties": {
          "broadcastId": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/BroadcastStatus"
          },
          "total": {
            "type": "integer",
            "description": "Total contacts in broadcast."
          },
          "pending": {
            "type": "integer",
            "description": "Not yet queued for sending."
          },
          "sending": {
            "type": "integer",
            "description": "Currently being sent."
          },
          "delivered": {
            "type": "integer",
            "description": "Successfully delivered."
          },
          "failed": {
            "type": "integer",
            "description": "Failed to deliver."
          },
          "skipped": {
            "type": "integer",
            "description": "Skipped (broadcast cancelled)."
          },
          "percentComplete": {
            "type": "number",
            "description": "Percentage complete (0-100)."
          },
          "estimatedCost": {
            "type": "number",
            "nullable": true,
            "description": "Estimated total cost in USD."
          },
          "reservedAmount": {
            "type": "number",
            "nullable": true,
            "description": "Amount reserved from balance in USD."
          },
          "actualCost": {
            "type": "number",
            "nullable": true,
            "description": "Actual cost so far in USD."
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "estimatedCompletionAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PhoneNumberStatus": {
        "type": "string",
        "enum": [
          "active",
          "suspended",
          "pending"
        ]
      },
      "PhoneNumberType": {
        "type": "string",
        "enum": [
          "local",
          "national",
          "tollFree"
        ]
      },
      "PhoneNumberCapabilities": {
        "type": "object",
        "properties": {
          "sms": {
            "type": "boolean"
          },
          "voice": {
            "type": "boolean"
          },
          "mms": {
            "type": "boolean"
          }
        }
      },
      "PhoneNumberPricing": {
        "type": "object",
        "properties": {
          "monthlyPrice": {
            "type": "number",
            "description": "Monthly price in USD."
          },
          "upfrontPrice": {
            "type": "number",
            "description": "One-time purchase price in USD."
          },
          "isFreeEligible": {
            "type": "boolean",
            "description": "Whether this number qualifies as the plan-included first US number on paid plans."
          }
        }
      },
      "AvailablePhoneNumber": {
        "type": "object",
        "required": [
          "phoneNumber",
          "capabilities",
          "pricing"
        ],
        "properties": {
          "phoneNumber": {
            "type": "string",
            "example": "+15551234567"
          },
          "friendlyName": {
            "type": "string",
            "example": "(555) 123-4567"
          },
          "locality": {
            "type": "string",
            "example": "San Francisco"
          },
          "region": {
            "type": "string",
            "example": "CA"
          },
          "capabilities": {
            "$ref": "#/components/schemas/PhoneNumberCapabilities"
          },
          "pricing": {
            "$ref": "#/components/schemas/PhoneNumberPricing"
          }
        }
      },
      "OwnedPhoneNumberPricing": {
        "type": "object",
        "properties": {
          "monthlyPrice": {
            "type": "number",
            "description": "Monthly price in USD."
          },
          "upfrontCost": {
            "type": "number",
            "description": "One-time purchase cost in cents."
          },
          "monthlyCost": {
            "type": "number",
            "description": "Monthly cost in cents."
          },
          "isFreeNumber": {
            "type": "boolean",
            "description": "Whether this is a free number."
          }
        }
      },
      "OwnedPhoneNumber": {
        "type": "object",
        "required": [
          "id",
          "phoneNumber",
          "capabilities",
          "status",
          "pricing",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "phoneNumber": {
            "type": "string",
            "example": "+15551234567"
          },
          "name": {
            "type": "string",
            "description": "Optional custom name for the phone number."
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "sms",
              "voice"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/PhoneNumberStatus"
          },
          "senderId": {
            "type": "string",
            "description": "Sender ID if the phone number is assigned to a sender."
          },
          "pricing": {
            "$ref": "#/components/schemas/OwnedPhoneNumberPricing"
          },
          "nextRenewalDate": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PhoneNumberPurchaseRequest": {
        "type": "object",
        "required": [
          "phoneNumber"
        ],
        "properties": {
          "phoneNumber": {
            "type": "string",
            "description": "Phone number in E.164 format.",
            "example": "+15551234567"
          },
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "Optional custom name for the phone number."
          }
        }
      },
      "PhoneNumberUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100,
            "nullable": true,
            "description": "Custom name for the phone number. Set to null to clear."
          },
          "senderId": {
            "type": "string",
            "nullable": true,
            "description": "Sender ID to assign the phone number to. Set to null to unassign."
          }
        }
      },
      "PhoneNumberResponse": {
        "type": "object",
        "required": [
          "phoneNumber"
        ],
        "properties": {
          "phoneNumber": {
            "$ref": "#/components/schemas/OwnedPhoneNumber"
          }
        }
      },
      "InvitationStatus": {
        "type": "string",
        "description": "Current status of the partner invitation.\n\n`failed` means the client started the connection and it did not finish (they cancelled Meta's dialog, denied a permission, or abandoned the tab). A failed invitation is still usable: the same link can be retried, and it moves back to `in_progress` when the client tries again.",
        "enum": [
          "pending",
          "in_progress",
          "completed",
          "expired",
          "cancelled",
          "failed"
        ]
      },
      "InvitationCreateRequest": {
        "type": "object",
        "properties": {
          "clientName": {
            "type": "string",
            "maxLength": 100,
            "description": "Name of the client being invited.",
            "example": "Acme Corp"
          },
          "clientEmail": {
            "type": "string",
            "format": "email",
            "description": "Email of the client being invited.",
            "example": "contact@acme.com"
          },
          "clientPhone": {
            "type": "string",
            "description": "Phone number of the client in E.164 format.",
            "example": "+14155551234"
          },
          "phoneNumberId": {
            "type": "string",
            "description": "ID of a Zavu phone number to pre-assign for WhatsApp registration. If provided, the client will use this number instead of their own. Only valid when `connectionType` is `whatsapp_waba` — sending it with `messenger` returns 400, since a Facebook Page has no phone number.",
            "example": "pn_abc123"
          },
          "expiresInDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "default": 7,
            "description": "Number of days until the invitation expires."
          },
          "allowedPhoneCountries": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "description": "ISO country codes for allowed phone numbers. Only valid when `connectionType` is `whatsapp_waba` — sending it with `messenger` returns 400.",
            "example": [
              "US",
              "MX"
            ]
          },
          "connectionType": {
            "type": "string",
            "enum": [
              "whatsapp_waba",
              "messenger"
            ],
            "default": "whatsapp_waba",
            "description": "Which Meta channel the client connects, and how.\n- `whatsapp_waba` (default): Meta's embedded signup links an official WhatsApp Business Account. Accepts `phoneNumberId` and `allowedPhoneCountries`.\n- `messenger`: the client authorizes with Facebook and picks a Facebook Page they administer. The Page's Messenger inbox — including Marketplace chats — is routed to Zavu. They must be an admin of at least one Page. A Page can only be connected to one Zavu project at a time: if the client picks a Page that another project already connected, the newer connection wins and the older one is disconnected.\n\nOne invitation connects one channel. To onboard a client on several channels, create one invitation per channel; each completes into its own sender."
          }
        }
      },
      "Invitation": {
        "type": "object",
        "required": [
          "id",
          "url",
          "token",
          "status",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "inv_abc123"
          },
          "url": {
            "type": "string",
            "description": "Full URL to share with the client.",
            "example": "https://dashboard.zavu.dev/invite/abc123xyz"
          },
          "token": {
            "type": "string",
            "description": "Unique invitation token."
          },
          "clientName": {
            "type": "string",
            "nullable": true
          },
          "clientEmail": {
            "type": "string",
            "nullable": true
          },
          "clientPhone": {
            "type": "string",
            "nullable": true
          },
          "phoneNumberId": {
            "type": "string",
            "nullable": true,
            "description": "ID of a pre-assigned Zavu phone number for WhatsApp registration. Always null for `messenger` invitations."
          },
          "connectionType": {
            "type": "string",
            "enum": [
              "whatsapp_waba",
              "messenger"
            ],
            "description": "Which Meta channel the client connects: `whatsapp_waba` (official WhatsApp Cloud API via embedded signup) or `messenger` (a Facebook Page's Messenger inbox, including Marketplace chats)."
          },
          "status": {
            "$ref": "#/components/schemas/InvitationStatus"
          },
          "senderId": {
            "type": "string",
            "nullable": true,
            "description": "ID of the sender created when invitation is completed."
          },
          "connectedAccount": {
            "type": "object",
            "nullable": true,
            "description": "The account the client linked, populated once the invitation is `completed`. Null before that. Use it to show the partner what was connected without fetching the sender.",
            "required": [
              "channel",
              "id"
            ],
            "properties": {
              "channel": {
                "type": "string",
                "enum": [
                  "whatsapp",
                  "messenger"
                ]
              },
              "id": {
                "type": "string",
                "description": "Provider-side identifier: the WhatsApp phone number ID, or the Facebook Page ID."
              },
              "name": {
                "type": "string",
                "nullable": true,
                "description": "Display name of the connected account: the WhatsApp verified name, or the Facebook Page name."
              }
            }
          },
          "failureReason": {
            "type": "string",
            "nullable": true,
            "description": "Stable code for why the last attempt failed, present when `status` is `failed`. Values include `fb_cancelled` (client closed Meta's dialog), `fb_not_authorized` (permission denied), `signup_abandoned` (started but never finished), `meta_no_pages` (the client administers no Facebook Page), and `internal_error`. Treat unknown codes as a generic failure."
          },
          "failedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "viewedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "startedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InvitationResponse": {
        "type": "object",
        "required": [
          "invitation"
        ],
        "properties": {
          "invitation": {
            "$ref": "#/components/schemas/Invitation"
          }
        }
      },
      "WhatsAppBusinessProfileVertical": {
        "type": "string",
        "description": "Business category for WhatsApp Business profile.",
        "enum": [
          "UNDEFINED",
          "OTHER",
          "AUTO",
          "BEAUTY",
          "APPAREL",
          "EDU",
          "ENTERTAIN",
          "EVENT_PLAN",
          "FINANCE",
          "GROCERY",
          "GOVT",
          "HOTEL",
          "HEALTH",
          "NONPROFIT",
          "PROF_SERVICES",
          "RETAIL",
          "TRAVEL",
          "RESTAURANT",
          "NOT_A_BIZ"
        ]
      },
      "WhatsAppBusinessProfile": {
        "type": "object",
        "description": "WhatsApp Business profile information.",
        "properties": {
          "about": {
            "type": "string",
            "description": "Short description of the business (max 139 characters).",
            "maxLength": 139,
            "example": "Succulent specialists!"
          },
          "address": {
            "type": "string",
            "description": "Physical address of the business (max 256 characters).",
            "maxLength": 256,
            "example": "1 Hacker Way, Menlo Park, CA 94025"
          },
          "description": {
            "type": "string",
            "description": "Extended description of the business (max 512 characters).",
            "maxLength": 512,
            "example": "At Lucky Shrub, we specialize in providing a diverse range of high-quality succulents."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Business email address.",
            "example": "contact@example.com"
          },
          "profilePictureUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL of the business profile picture.",
            "example": "https://pps.whatsapp.net/v/t61.24..."
          },
          "websites": {
            "type": "array",
            "description": "Business website URLs (maximum 2).",
            "maxItems": 2,
            "items": {
              "type": "string",
              "format": "uri"
            },
            "example": [
              "https://www.example.com/"
            ]
          },
          "vertical": {
            "$ref": "#/components/schemas/WhatsAppBusinessProfileVertical"
          }
        }
      },
      "WhatsAppBusinessProfileUpdateRequest": {
        "type": "object",
        "description": "Request body to update WhatsApp Business profile.",
        "properties": {
          "about": {
            "type": "string",
            "description": "Short description of the business (max 139 characters).",
            "maxLength": 139
          },
          "address": {
            "type": "string",
            "description": "Physical address of the business (max 256 characters).",
            "maxLength": 256
          },
          "description": {
            "type": "string",
            "description": "Extended description of the business (max 512 characters).",
            "maxLength": 512
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Business email address."
          },
          "websites": {
            "type": "array",
            "description": "Business website URLs (maximum 2).",
            "maxItems": 2,
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "vertical": {
            "$ref": "#/components/schemas/WhatsAppBusinessProfileVertical"
          }
        }
      },
      "WhatsAppBusinessProfileResponse": {
        "type": "object",
        "required": [
          "profile"
        ],
        "properties": {
          "profile": {
            "$ref": "#/components/schemas/WhatsAppBusinessProfile"
          }
        }
      },
      "WhatsAppBusinessProfilePictureRequest": {
        "type": "object",
        "description": "Request body to upload a profile picture.",
        "required": [
          "imageUrl",
          "mimeType"
        ],
        "properties": {
          "imageUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL of the image to upload."
          },
          "mimeType": {
            "type": "string",
            "description": "MIME type of the image.",
            "enum": [
              "image/jpeg",
              "image/png"
            ]
          }
        }
      },
      "WhatsAppSyncHistoryStatus": {
        "type": "string",
        "description": "Status of WhatsApp message history sync.",
        "enum": [
          "not_requested",
          "pending",
          "syncing",
          "completed",
          "rejected"
        ]
      },
      "WhatsAppSyncContactsStatus": {
        "type": "string",
        "description": "Status of WhatsApp contacts sync.",
        "enum": [
          "not_requested",
          "pending",
          "syncing",
          "completed"
        ]
      },
      "WhatsAppSyncHistory": {
        "type": "object",
        "description": "History sync status details.",
        "required": [
          "status",
          "canSync"
        ],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/WhatsAppSyncHistoryStatus"
          },
          "canSync": {
            "type": "boolean",
            "description": "Whether history sync can be initiated."
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the sync was last requested."
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the sync was completed."
          }
        }
      },
      "WhatsAppSyncContacts": {
        "type": "object",
        "description": "Contacts sync status details.",
        "required": [
          "status",
          "canSync"
        ],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/WhatsAppSyncContactsStatus"
          },
          "canSync": {
            "type": "boolean",
            "description": "Whether contacts sync can be initiated."
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the sync was last requested."
          }
        }
      },
      "WhatsAppSyncStatus": {
        "type": "object",
        "description": "WhatsApp coexistence sync status.",
        "required": [
          "isCoexistence",
          "status",
          "history",
          "contacts"
        ],
        "properties": {
          "isCoexistence": {
            "type": "boolean",
            "description": "Whether the account is in coexistence mode."
          },
          "status": {
            "type": "string",
            "description": "WhatsApp account status.",
            "enum": [
              "pending_verification",
              "pending_registration",
              "active",
              "disconnected",
              "error"
            ]
          },
          "history": {
            "$ref": "#/components/schemas/WhatsAppSyncHistory"
          },
          "contacts": {
            "$ref": "#/components/schemas/WhatsAppSyncContacts"
          }
        }
      },
      "WhatsAppSyncStatusResponse": {
        "type": "object",
        "required": [
          "sync"
        ],
        "properties": {
          "sync": {
            "$ref": "#/components/schemas/WhatsAppSyncStatus"
          }
        }
      },
      "WhatsAppSyncStartResponse": {
        "type": "object",
        "required": [
          "message",
          "sync"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Success message.",
            "example": "History sync initiated"
          },
          "sync": {
            "$ref": "#/components/schemas/WhatsAppSyncStatus"
          }
        }
      },
      "AgentProvider": {
        "type": "string",
        "description": "LLM provider for the AI agent.",
        "enum": [
          "openai",
          "anthropic",
          "google",
          "mistral",
          "zavu"
        ]
      },
      "AgentExecutionStatus": {
        "type": "string",
        "description": "Status of an agent execution.",
        "enum": [
          "success",
          "error",
          "filtered",
          "rate_limited",
          "balance_insufficient"
        ]
      },
      "Agent": {
        "type": "object",
        "description": "AI Agent configuration for a sender.",
        "required": [
          "id",
          "senderId",
          "name",
          "enabled",
          "provider",
          "model",
          "systemPrompt",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "agent_abc123"
          },
          "senderId": {
            "type": "string",
            "example": "sender_12345"
          },
          "name": {
            "type": "string",
            "example": "Customer Support Agent"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the agent is active."
          },
          "provider": {
            "$ref": "#/components/schemas/AgentProvider"
          },
          "model": {
            "type": "string",
            "description": "Model ID (e.g., gpt-4o-mini, claude-3-5-sonnet).",
            "example": "gpt-4o-mini"
          },
          "systemPrompt": {
            "type": "string",
            "description": "System prompt for the agent."
          },
          "contextWindowMessages": {
            "type": "integer",
            "description": "Number of previous messages to include as context.",
            "default": 10
          },
          "includeContactMetadata": {
            "type": "boolean",
            "description": "Whether to include contact metadata in context.",
            "default": true
          },
          "maxTokens": {
            "type": "integer",
            "description": "Maximum tokens for LLM response.",
            "nullable": true
          },
          "temperature": {
            "type": "number",
            "description": "LLM temperature (0-2).",
            "nullable": true
          },
          "triggerOnChannels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Channels that trigger the agent.",
            "example": [
              "sms",
              "whatsapp"
            ]
          },
          "triggerOnMessageTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Message types that trigger the agent.",
            "example": [
              "text"
            ]
          },
          "stats": {
            "type": "object",
            "properties": {
              "totalInvocations": {
                "type": "integer"
              },
              "totalTokensUsed": {
                "type": "integer"
              },
              "totalCost": {
                "type": "number",
                "description": "Total cost in USD."
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "voice": {
            "$ref": "#/components/schemas/AgentVoiceConfig",
            "description": "Voice Agent configuration. When present and enabled, the agent can answer inbound phone calls and place outbound calls with Zavu's managed voice pipeline. Requires the Voice Agents feature to be enabled for your team."
          },
          "senderIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Senders this agent answers on. An agent can serve several; `senderId` remains the primary one, for compatibility."
          }
        }
      },
      "AgentCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "provider",
          "model",
          "systemPrompt"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "provider": {
            "$ref": "#/components/schemas/AgentProvider"
          },
          "model": {
            "type": "string"
          },
          "systemPrompt": {
            "type": "string",
            "maxLength": 10000
          },
          "apiKey": {
            "type": "string",
            "description": "API key for the LLM provider. Required unless provider is 'zavu'."
          },
          "contextWindowMessages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 10
          },
          "includeContactMetadata": {
            "type": "boolean",
            "default": true
          },
          "maxTokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 4096
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2
          },
          "triggerOnChannels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": [
              "*"
            ]
          },
          "triggerOnMessageTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": [
              "text"
            ]
          },
          "voice": {
            "$ref": "#/components/schemas/AgentVoiceConfig",
            "description": "Voice Agent configuration. Enable this to let the agent answer and place phone calls with Zavu's managed voice pipeline. Requires the Voice Agents feature to be enabled for your team."
          }
        }
      },
      "AgentUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "enabled": {
            "type": "boolean"
          },
          "provider": {
            "$ref": "#/components/schemas/AgentProvider"
          },
          "model": {
            "type": "string"
          },
          "systemPrompt": {
            "type": "string",
            "maxLength": 10000
          },
          "apiKey": {
            "type": "string"
          },
          "contextWindowMessages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "includeContactMetadata": {
            "type": "boolean"
          },
          "maxTokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 4096,
            "nullable": true
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2,
            "nullable": true
          },
          "triggerOnChannels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "triggerOnMessageTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "voice": {
            "$ref": "#/components/schemas/AgentVoiceConfig",
            "description": "Voice Agent configuration. Patch this object to enable voice, change the greeting, or adjust call limits. Requires the Voice Agents feature to be enabled for your team."
          }
        }
      },
      "AgentResponse": {
        "type": "object",
        "required": [
          "agent"
        ],
        "properties": {
          "agent": {
            "$ref": "#/components/schemas/Agent"
          }
        }
      },
      "AgentStats": {
        "type": "object",
        "required": [
          "totalInvocations",
          "totalTokensUsed",
          "totalCost",
          "successCount",
          "errorCount"
        ],
        "properties": {
          "totalInvocations": {
            "type": "integer"
          },
          "totalTokensUsed": {
            "type": "integer"
          },
          "totalCost": {
            "type": "number",
            "description": "Total cost in USD."
          },
          "successCount": {
            "type": "integer"
          },
          "errorCount": {
            "type": "integer"
          },
          "avgLatencyMs": {
            "type": "number",
            "nullable": true
          }
        }
      },
      "AgentExecution": {
        "type": "object",
        "required": [
          "id",
          "agentId",
          "status",
          "inputTokens",
          "outputTokens",
          "latencyMs",
          "cost",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "agentId": {
            "type": "string"
          },
          "inboundMessageId": {
            "type": "string"
          },
          "responseMessageId": {
            "type": "string",
            "nullable": true
          },
          "responseText": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/AgentExecutionStatus"
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "inputTokens": {
            "type": "integer"
          },
          "outputTokens": {
            "type": "integer"
          },
          "latencyMs": {
            "type": "integer"
          },
          "cost": {
            "type": "number",
            "description": "Cost in USD."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "knowledgeChunksUsed": {
            "type": "integer",
            "nullable": true,
            "description": "Knowledge-base chunks retrieved for this answer. Zero on an agent that has documents attached means the reply was not grounded in them, which is otherwise indistinguishable from a correct answer in this record. Absent on executions recorded before this field existed, which is not the same as zero."
          },
          "toolCalls": {
            "type": "integer",
            "nullable": true,
            "description": "Tools the agent called while producing this reply. Zero on an agent that has tools configured means it answered without calling any — the case where a reply says it will look something up and nothing ever reaches your endpoint. Absent on executions recorded before this field existed, which is not the same as zero."
          }
        }
      },
      "FlowTriggerType": {
        "type": "string",
        "description": "Type of trigger for a flow.",
        "enum": [
          "keyword",
          "intent",
          "always",
          "manual"
        ]
      },
      "FlowStepType": {
        "type": "string",
        "description": "Type of flow step.",
        "enum": [
          "message",
          "collect",
          "condition",
          "tool",
          "llm",
          "transfer"
        ]
      },
      "FlowTrigger": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/FlowTriggerType"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Keywords that trigger the flow (for keyword type)."
          },
          "intent": {
            "type": "string",
            "description": "Intent that triggers the flow (for intent type)."
          }
        }
      },
      "FlowStep": {
        "type": "object",
        "required": [
          "id",
          "type",
          "config"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique step identifier."
          },
          "type": {
            "$ref": "#/components/schemas/FlowStepType"
          },
          "config": {
            "type": "object",
            "description": "Step configuration (varies by type).",
            "additionalProperties": true
          },
          "nextStepId": {
            "type": "string",
            "description": "ID of the next step to execute.",
            "nullable": true
          }
        }
      },
      "AgentFlow": {
        "type": "object",
        "required": [
          "id",
          "agentId",
          "name",
          "trigger",
          "steps",
          "enabled",
          "priority",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "agentId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "trigger": {
            "$ref": "#/components/schemas/FlowTrigger"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlowStep"
            }
          },
          "enabled": {
            "type": "boolean"
          },
          "priority": {
            "type": "integer",
            "description": "Priority when multiple flows match (higher = more priority)."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FlowCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "trigger",
          "steps"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string"
          },
          "trigger": {
            "$ref": "#/components/schemas/FlowTrigger"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlowStep"
            },
            "minItems": 1
          },
          "enabled": {
            "type": "boolean",
            "default": false
          },
          "priority": {
            "type": "integer",
            "default": 0
          }
        }
      },
      "FlowUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string"
          },
          "trigger": {
            "$ref": "#/components/schemas/FlowTrigger"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlowStep"
            },
            "minItems": 1
          },
          "enabled": {
            "type": "boolean"
          },
          "priority": {
            "type": "integer"
          }
        }
      },
      "FlowResponse": {
        "type": "object",
        "required": [
          "flow"
        ],
        "properties": {
          "flow": {
            "$ref": "#/components/schemas/AgentFlow"
          }
        }
      },
      "FlowDuplicateRequest": {
        "type": "object",
        "required": [
          "newName"
        ],
        "properties": {
          "newName": {
            "type": "string",
            "maxLength": 100
          }
        }
      },
      "ToolParameters": {
        "type": "object",
        "required": [
          "type",
          "properties",
          "required"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "object"
            ]
          },
          "properties": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "required": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AgentTool": {
        "type": "object",
        "required": [
          "id",
          "agentId",
          "name",
          "description",
          "parameters",
          "webhookUrl",
          "enabled",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "agentId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "get_order_status"
          },
          "description": {
            "type": "string",
            "description": "Description for the LLM to understand when to use this tool."
          },
          "parameters": {
            "$ref": "#/components/schemas/ToolParameters"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL to call when the tool is executed."
          },
          "enabled": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "webhookSecret": {
            "type": "string",
            "description": "Signing secret for this tool's webhook. **Returned only when the tool is created**, never on a later read.\n\nZavu generates one if you do not supply it, and signs every call to this tool with it: `X-Zavu-Signature: <hex>`, the HMAC-SHA256 of the request body. Verify it before trusting the call. Lost it? Rotate with `POST /v1/senders/{senderId}/agent/tools/{toolId}/webhook/secret`.",
            "example": "whsec_abc123..."
          }
        }
      },
      "ToolCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "description",
          "parameters",
          "webhookUrl"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "parameters": {
            "$ref": "#/components/schemas/ToolParameters"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "description": "Must be HTTPS."
          },
          "webhookSecret": {
            "type": "string",
            "description": "Signing secret for the webhook. Optional: Zavu generates one when omitted and returns it on this response only. Supply your own if you already have a secret you want reused."
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "ToolUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "parameters": {
            "$ref": "#/components/schemas/ToolParameters"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri"
          },
          "webhookSecret": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "ToolResponse": {
        "type": "object",
        "required": [
          "tool"
        ],
        "properties": {
          "tool": {
            "$ref": "#/components/schemas/AgentTool"
          }
        }
      },
      "ToolTestRequest": {
        "type": "object",
        "required": [
          "testParams"
        ],
        "properties": {
          "testParams": {
            "type": "object",
            "description": "Parameters to pass to the tool for testing.",
            "additionalProperties": true
          }
        }
      },
      "AgentToolTestRun": {
        "type": "object",
        "description": "One run of a tool triggered from the test endpoint. Recorded so a test is verifiable after the fact rather than only visible in the response.",
        "required": [
          "id",
          "toolId",
          "success",
          "durationMs",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "toolId": {
            "type": "string"
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "The parameters the tool was called with."
          },
          "success": {
            "type": "boolean",
            "description": "Whether the tool returned without error. A tool that answered with a non-2xx status is a failed run, not an error of this endpoint."
          },
          "statusCode": {
            "type": "integer",
            "nullable": true,
            "description": "HTTP status the tool's webhook returned. Absent for tools that do not go over HTTP."
          },
          "response": {
            "type": "string",
            "nullable": true,
            "description": "The tool's response body, truncated."
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Why the run failed, when it did."
          },
          "durationMs": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ToolTestResponse": {
        "type": "object",
        "required": [
          "run"
        ],
        "properties": {
          "run": {
            "$ref": "#/components/schemas/AgentToolTestRun"
          }
        }
      },
      "AgentKnowledgeBase": {
        "type": "object",
        "required": [
          "id",
          "agentId",
          "name",
          "documentCount",
          "totalChunks",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "agentId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "documentCount": {
            "type": "integer"
          },
          "totalChunks": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "KnowledgeBaseCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string"
          }
        }
      },
      "KnowledgeBaseUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "KnowledgeBaseResponse": {
        "type": "object",
        "required": [
          "knowledgeBase"
        ],
        "properties": {
          "knowledgeBase": {
            "$ref": "#/components/schemas/AgentKnowledgeBase"
          }
        }
      },
      "AgentDocument": {
        "type": "object",
        "required": [
          "id",
          "knowledgeBaseId",
          "title",
          "contentLength",
          "chunkCount",
          "isProcessed",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "knowledgeBaseId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "contentLength": {
            "type": "integer",
            "description": "Length of the document content in characters."
          },
          "chunkCount": {
            "type": "integer",
            "description": "Number of chunks created from this document."
          },
          "isProcessed": {
            "type": "boolean",
            "description": "Whether the document has been processed for RAG."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DocumentCreateRequest": {
        "type": "object",
        "required": [
          "title",
          "content"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 200
          },
          "content": {
            "type": "string",
            "maxLength": 100000
          }
        }
      },
      "DocumentResponse": {
        "type": "object",
        "required": [
          "document"
        ],
        "properties": {
          "document": {
            "$ref": "#/components/schemas/AgentDocument"
          }
        }
      },
      "RequirementFieldType": {
        "type": "string",
        "description": "Type of requirement field.",
        "enum": [
          "textual",
          "address",
          "document",
          "action"
        ]
      },
      "RequirementAcceptanceCriteria": {
        "type": "object",
        "description": "Acceptance criteria for a requirement.",
        "properties": {
          "minLength": {
            "type": "integer",
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "nullable": true
          },
          "allowedValues": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "regexPattern": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RequirementType": {
        "type": "object",
        "description": "A specific requirement type within a requirement group.",
        "required": [
          "id",
          "name",
          "description",
          "type"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/RequirementFieldType"
          },
          "example": {
            "type": "string",
            "nullable": true
          },
          "acceptanceCriteria": {
            "$ref": "#/components/schemas/RequirementAcceptanceCriteria"
          }
        }
      },
      "Requirement": {
        "type": "object",
        "description": "A group of requirements for a specific country/phone type combination.",
        "required": [
          "id",
          "countryCode",
          "phoneNumberType",
          "action",
          "requirementTypes"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "countryCode": {
            "type": "string",
            "example": "DE"
          },
          "phoneNumberType": {
            "type": "string",
            "example": "local"
          },
          "action": {
            "type": "string",
            "example": "ordering"
          },
          "requirementTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RequirementType"
            }
          }
        }
      },
      "AddressStatus": {
        "type": "string",
        "enum": [
          "pending",
          "verified",
          "rejected"
        ]
      },
      "Address": {
        "type": "object",
        "description": "A regulatory address for phone number requirements.",
        "required": [
          "id",
          "streetAddress",
          "locality",
          "postalCode",
          "countryCode",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "businessName": {
            "type": "string",
            "nullable": true
          },
          "streetAddress": {
            "type": "string"
          },
          "extendedAddress": {
            "type": "string",
            "nullable": true
          },
          "locality": {
            "type": "string"
          },
          "administrativeArea": {
            "type": "string",
            "nullable": true
          },
          "postalCode": {
            "type": "string"
          },
          "countryCode": {
            "type": "string",
            "example": "DE"
          },
          "status": {
            "$ref": "#/components/schemas/AddressStatus"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AddressCreateRequest": {
        "type": "object",
        "required": [
          "streetAddress",
          "locality",
          "postalCode",
          "countryCode"
        ],
        "properties": {
          "firstName": {
            "type": "string",
            "maxLength": 100
          },
          "lastName": {
            "type": "string",
            "maxLength": 100
          },
          "businessName": {
            "type": "string",
            "maxLength": 200
          },
          "streetAddress": {
            "type": "string",
            "maxLength": 200
          },
          "extendedAddress": {
            "type": "string",
            "maxLength": 100
          },
          "locality": {
            "type": "string",
            "maxLength": 100
          },
          "administrativeArea": {
            "type": "string",
            "maxLength": 100
          },
          "postalCode": {
            "type": "string",
            "maxLength": 20
          },
          "countryCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "example": "DE"
          }
        }
      },
      "AddressResponse": {
        "type": "object",
        "required": [
          "address"
        ],
        "properties": {
          "address": {
            "$ref": "#/components/schemas/Address"
          }
        }
      },
      "RegulatoryDocumentStatus": {
        "type": "string",
        "enum": [
          "pending",
          "uploaded",
          "verified",
          "rejected"
        ]
      },
      "RegulatoryDocumentType": {
        "type": "string",
        "enum": [
          "passport",
          "national_id",
          "drivers_license",
          "utility_bill",
          "tax_id",
          "business_registration",
          "proof_of_address",
          "other"
        ]
      },
      "RegulatoryDocument": {
        "type": "object",
        "description": "A regulatory document for phone number requirements.",
        "required": [
          "id",
          "name",
          "documentType",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "documentType": {
            "$ref": "#/components/schemas/RegulatoryDocumentType"
          },
          "mimeType": {
            "type": "string"
          },
          "fileSize": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/RegulatoryDocumentStatus"
          },
          "rejectionReason": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RegulatoryDocumentCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "documentType",
          "storageId",
          "mimeType",
          "fileSize"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "documentType": {
            "$ref": "#/components/schemas/RegulatoryDocumentType"
          },
          "storageId": {
            "type": "string",
            "description": "Storage ID from the upload-url endpoint."
          },
          "mimeType": {
            "type": "string"
          },
          "fileSize": {
            "type": "integer"
          }
        }
      },
      "RegulatoryDocumentResponse": {
        "type": "object",
        "required": [
          "document"
        ],
        "properties": {
          "document": {
            "$ref": "#/components/schemas/RegulatoryDocument"
          }
        }
      },
      "UploadUrlResponse": {
        "type": "object",
        "required": [
          "uploadUrl"
        ],
        "properties": {
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "description": "Pre-signed URL for uploading the file."
          }
        }
      },
      "VerifiedUrlStatus": {
        "type": "string",
        "description": "Status of a verified URL.",
        "enum": [
          "pending",
          "approved",
          "rejected",
          "escalated",
          "malicious"
        ]
      },
      "VerifiedUrlApprovalType": {
        "type": "string",
        "description": "How the URL was approved or rejected.",
        "enum": [
          "manual",
          "auto_web_risk"
        ]
      },
      "VerifiedUrl": {
        "type": "object",
        "required": [
          "id",
          "url",
          "domain",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "url_abc123"
          },
          "url": {
            "type": "string",
            "description": "The verified URL.",
            "example": "https://example.com/page"
          },
          "domain": {
            "type": "string",
            "description": "Domain extracted from the URL.",
            "example": "example.com"
          },
          "status": {
            "$ref": "#/components/schemas/VerifiedUrlStatus"
          },
          "approvalType": {
            "$ref": "#/components/schemas/VerifiedUrlApprovalType"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VerifiedUrlSubmitRequest": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "The URL to submit for verification.",
            "example": "https://example.com/page"
          }
        }
      },
      "VerifiedUrlResponse": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "$ref": "#/components/schemas/VerifiedUrl"
          }
        }
      },
      "SubAccountStatus": {
        "type": "string",
        "enum": [
          "active",
          "inactive"
        ]
      },
      "SubAccount": {
        "type": "object",
        "required": [
          "id",
          "name",
          "status",
          "totalSpent",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Client ABC"
          },
          "externalId": {
            "type": "string",
            "nullable": true,
            "description": "External reference ID set by the parent account."
          },
          "status": {
            "$ref": "#/components/schemas/SubAccountStatus"
          },
          "totalSpent": {
            "type": "integer",
            "description": "Total amount spent by this sub-account in cents."
          },
          "creditLimit": {
            "type": "integer",
            "nullable": true,
            "description": "Spending cap in cents. When reached, messages from this sub-account will be blocked."
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          },
          "apiKey": {
            "type": "string",
            "description": "API key for the sub-account. Only returned on creation."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SubAccountCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "Name of the sub-account.",
            "example": "Client ABC"
          },
          "externalId": {
            "type": "string",
            "description": "External reference ID for your own tracking."
          },
          "creditLimit": {
            "type": "integer",
            "minimum": 0,
            "description": "Spending cap in cents. When reached, messages from this sub-account will be blocked. Omit or set to 0 for no limit."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "SubAccountUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "creditLimit": {
            "type": "integer",
            "nullable": true,
            "minimum": 0
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "status": {
            "$ref": "#/components/schemas/SubAccountStatus"
          }
        }
      },
      "SubAccountResponse": {
        "type": "object",
        "required": [
          "subAccount"
        ],
        "properties": {
          "subAccount": {
            "$ref": "#/components/schemas/SubAccount"
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "required": [
          "balance",
          "currency"
        ],
        "properties": {
          "balance": {
            "type": "integer",
            "description": "Team balance in cents. All charges are billed to the parent team."
          },
          "currency": {
            "type": "string",
            "example": "usd"
          },
          "creditLimit": {
            "type": "integer",
            "nullable": true,
            "description": "Spending cap in cents (only for sub-accounts)."
          },
          "totalSpent": {
            "type": "integer",
            "nullable": true,
            "description": "Total amount spent by this sub-account in cents (only for sub-accounts)."
          },
          "isSubAccount": {
            "type": "boolean",
            "description": "Whether this API key belongs to a sub-account."
          }
        }
      },
      "SubAccountApiKey": {
        "type": "object",
        "required": [
          "id",
          "name",
          "keyPrefix",
          "environment",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "description": "Full API key. Only returned on creation."
          },
          "keyPrefix": {
            "type": "string",
            "description": "First characters of the key for identification."
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "lastUsedAt": {
            "type": "number",
            "nullable": true
          },
          "revokedAt": {
            "type": "number",
            "nullable": true
          },
          "createdAt": {
            "type": "number"
          }
        }
      },
      "SubAccountApiKeyCreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "environment": {
            "type": "string",
            "enum": [
              "live",
              "test"
            ],
            "default": "live"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "TenDlcEntityType": {
        "type": "string",
        "description": "Business entity type for 10DLC brand registration.",
        "enum": [
          "PRIVATE_PROFIT",
          "PUBLIC_PROFIT",
          "NON_PROFIT",
          "GOVERNMENT",
          "SOLE_PROPRIETOR"
        ]
      },
      "TenDlcBrandStatus": {
        "type": "string",
        "description": "Status of a 10DLC brand registration.",
        "enum": [
          "draft",
          "pending",
          "verified",
          "rejected"
        ]
      },
      "TenDlcBrand": {
        "type": "object",
        "required": [
          "id",
          "entityType",
          "displayName",
          "email",
          "phone",
          "street",
          "city",
          "state",
          "postalCode",
          "country",
          "vertical",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "entityType": {
            "$ref": "#/components/schemas/TenDlcEntityType"
          },
          "displayName": {
            "type": "string",
            "description": "Display name of the brand.",
            "example": "Acme Corp"
          },
          "companyName": {
            "type": "string",
            "nullable": true,
            "description": "Legal company name."
          },
          "ein": {
            "type": "string",
            "nullable": true,
            "description": "Employer Identification Number (EIN).",
            "example": "12-3456789"
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "description": "Contact phone number in E.164 format.",
            "example": "+14155551234"
          },
          "street": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "postalCode": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "description": "Two-letter ISO country code.",
            "example": "US"
          },
          "website": {
            "type": "string",
            "nullable": true,
            "format": "uri"
          },
          "vertical": {
            "type": "string",
            "description": "Industry vertical.",
            "example": "Technology"
          },
          "stockSymbol": {
            "type": "string",
            "nullable": true
          },
          "stockExchange": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TenDlcBrandStatus"
          },
          "brandScore": {
            "type": "integer",
            "nullable": true,
            "description": "Trust score assigned by TCR after vetting."
          },
          "brandRelationship": {
            "type": "string",
            "nullable": true
          },
          "failureReason": {
            "type": "string",
            "nullable": true,
            "description": "Reason for rejection, if applicable."
          },
          "submittedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "verifiedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TenDlcBrandCreateRequest": {
        "type": "object",
        "required": [
          "entityType",
          "displayName",
          "email",
          "phone",
          "street",
          "city",
          "state",
          "postalCode",
          "country",
          "vertical"
        ],
        "properties": {
          "entityType": {
            "$ref": "#/components/schemas/TenDlcEntityType"
          },
          "displayName": {
            "type": "string",
            "maxLength": 100,
            "description": "Display name of the brand.",
            "example": "Acme Corp"
          },
          "companyName": {
            "type": "string",
            "maxLength": 200,
            "description": "Legal company name."
          },
          "ein": {
            "type": "string",
            "description": "Employer Identification Number (format: XX-XXXXXXX).",
            "example": "12-3456789"
          },
          "firstName": {
            "type": "string",
            "maxLength": 50
          },
          "lastName": {
            "type": "string",
            "maxLength": 50
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "description": "Contact phone in E.164 format.",
            "example": "+14155551234"
          },
          "street": {
            "type": "string",
            "maxLength": 200
          },
          "city": {
            "type": "string",
            "maxLength": 100
          },
          "state": {
            "type": "string",
            "maxLength": 50
          },
          "postalCode": {
            "type": "string",
            "maxLength": 20
          },
          "country": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "Two-letter ISO country code.",
            "example": "US"
          },
          "website": {
            "type": "string",
            "format": "uri"
          },
          "vertical": {
            "type": "string",
            "maxLength": 50,
            "description": "Industry vertical.",
            "example": "Technology"
          },
          "stockSymbol": {
            "type": "string",
            "maxLength": 10
          },
          "stockExchange": {
            "type": "string",
            "maxLength": 50
          }
        }
      },
      "TenDlcBrandUpdateRequest": {
        "type": "object",
        "properties": {
          "entityType": {
            "$ref": "#/components/schemas/TenDlcEntityType"
          },
          "displayName": {
            "type": "string",
            "maxLength": 100
          },
          "companyName": {
            "type": "string",
            "maxLength": 200
          },
          "ein": {
            "type": "string"
          },
          "firstName": {
            "type": "string",
            "maxLength": 50
          },
          "lastName": {
            "type": "string",
            "maxLength": 50
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "street": {
            "type": "string",
            "maxLength": 200
          },
          "city": {
            "type": "string",
            "maxLength": 100
          },
          "state": {
            "type": "string",
            "maxLength": 50
          },
          "postalCode": {
            "type": "string",
            "maxLength": 20
          },
          "country": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2
          },
          "website": {
            "type": "string",
            "format": "uri"
          },
          "vertical": {
            "type": "string",
            "maxLength": 50
          },
          "stockSymbol": {
            "type": "string",
            "maxLength": 10
          },
          "stockExchange": {
            "type": "string",
            "maxLength": 50
          }
        }
      },
      "TenDlcBrandResponse": {
        "type": "object",
        "required": [
          "brand"
        ],
        "properties": {
          "brand": {
            "$ref": "#/components/schemas/TenDlcBrand"
          }
        }
      },
      "TenDlcCampaignStatus": {
        "type": "string",
        "description": "Status of a 10DLC campaign registration.",
        "enum": [
          "draft",
          "pending",
          "approved",
          "rejected"
        ]
      },
      "TenDlcCampaign": {
        "type": "object",
        "required": [
          "id",
          "brandId",
          "name",
          "useCase",
          "description",
          "sampleMessages",
          "subscriberOptIn",
          "subscriberOptOut",
          "subscriberHelp",
          "numberPooling",
          "directLending",
          "embeddedLink",
          "embeddedPhone",
          "affiliateMarketing",
          "ageGated",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "brandId": {
            "type": "string",
            "description": "ID of the brand this campaign belongs to."
          },
          "name": {
            "type": "string",
            "example": "Order Notifications"
          },
          "useCase": {
            "type": "string",
            "description": "Campaign use case type.",
            "example": "ACCOUNT_NOTIFICATION"
          },
          "subUseCases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Description of the messaging campaign."
          },
          "sampleMessages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Sample messages representative of campaign content."
          },
          "subscriberOptIn": {
            "type": "boolean"
          },
          "subscriberOptOut": {
            "type": "boolean"
          },
          "subscriberHelp": {
            "type": "boolean"
          },
          "numberPooling": {
            "type": "boolean"
          },
          "directLending": {
            "type": "boolean"
          },
          "embeddedLink": {
            "type": "boolean"
          },
          "embeddedPhone": {
            "type": "boolean"
          },
          "affiliateMarketing": {
            "type": "boolean"
          },
          "ageGated": {
            "type": "boolean"
          },
          "messageFlow": {
            "type": "string",
            "nullable": true
          },
          "helpMessage": {
            "type": "string",
            "nullable": true
          },
          "optInKeywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "optOutKeywords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TenDlcCampaignStatus"
          },
          "dailyLimit": {
            "type": "integer",
            "nullable": true,
            "description": "Daily message limit based on brand trust score."
          },
          "failureReason": {
            "type": "string",
            "nullable": true
          },
          "registrationCostCents": {
            "type": "integer",
            "nullable": true,
            "description": "One-time registration cost in cents."
          },
          "monthlyFeeCents": {
            "type": "integer",
            "nullable": true,
            "description": "Recurring monthly fee in cents."
          },
          "submittedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "approvedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TenDlcCampaignCreateRequest": {
        "type": "object",
        "required": [
          "brandId",
          "name",
          "useCase",
          "description",
          "sampleMessages",
          "subscriberOptIn",
          "subscriberOptOut",
          "subscriberHelp",
          "numberPooling",
          "directLending",
          "embeddedLink",
          "embeddedPhone",
          "affiliateMarketing",
          "ageGated"
        ],
        "properties": {
          "brandId": {
            "type": "string",
            "description": "ID of the brand to create this campaign under."
          },
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "useCase": {
            "type": "string",
            "maxLength": 50,
            "description": "Campaign use case (e.g., ACCOUNT_NOTIFICATION, MARKETING, 2FA)."
          },
          "subUseCases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": {
            "type": "string",
            "maxLength": 4096
          },
          "sampleMessages": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 1024
            },
            "minItems": 1,
            "maxItems": 5
          },
          "subscriberOptIn": {
            "type": "boolean"
          },
          "subscriberOptOut": {
            "type": "boolean"
          },
          "subscriberHelp": {
            "type": "boolean"
          },
          "numberPooling": {
            "type": "boolean"
          },
          "directLending": {
            "type": "boolean"
          },
          "embeddedLink": {
            "type": "boolean"
          },
          "embeddedPhone": {
            "type": "boolean"
          },
          "affiliateMarketing": {
            "type": "boolean"
          },
          "ageGated": {
            "type": "boolean"
          },
          "messageFlow": {
            "type": "string",
            "maxLength": 2048
          },
          "helpMessage": {
            "type": "string",
            "maxLength": 500
          },
          "optInKeywords": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 50
            }
          },
          "optOutKeywords": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 50
            }
          }
        }
      },
      "TenDlcCampaignUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "description": {
            "type": "string",
            "maxLength": 4096
          },
          "sampleMessages": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 1024
            },
            "minItems": 1,
            "maxItems": 5
          },
          "messageFlow": {
            "type": "string",
            "maxLength": 2048
          },
          "helpMessage": {
            "type": "string",
            "maxLength": 500
          },
          "optInKeywords": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 50
            }
          },
          "optOutKeywords": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 50
            }
          }
        }
      },
      "TenDlcCampaignResponse": {
        "type": "object",
        "required": [
          "campaign"
        ],
        "properties": {
          "campaign": {
            "$ref": "#/components/schemas/TenDlcCampaign"
          }
        }
      },
      "TenDlcPhoneNumberAssignment": {
        "type": "object",
        "required": [
          "id",
          "campaignId",
          "phoneNumberId",
          "status",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "campaignId": {
            "type": "string"
          },
          "phoneNumberId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Assignment status.",
            "enum": [
              "pending",
              "active",
              "failed"
            ]
          },
          "failureReason": {
            "type": "string",
            "nullable": true
          },
          "assignedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TenDlcPhoneNumberAssignRequest": {
        "type": "object",
        "required": [
          "phoneNumberId"
        ],
        "properties": {
          "phoneNumberId": {
            "type": "string",
            "description": "ID of the phone number to assign."
          }
        }
      },
      "TenDlcAssignmentResponse": {
        "type": "object",
        "required": [
          "assignment"
        ],
        "properties": {
          "assignment": {
            "$ref": "#/components/schemas/TenDlcPhoneNumberAssignment"
          }
        }
      },
      "ZavuFunctionStatus": {
        "type": "string",
        "description": "Lifecycle status of a Zavu Function.",
        "enum": [
          "draft",
          "bundling",
          "deploying",
          "active",
          "failed",
          "disabled"
        ]
      },
      "ZavuFunctionRuntime": {
        "type": "string",
        "description": "Runtime the function is deployed on.",
        "enum": [
          "nodejs24"
        ]
      },
      "ZavuFunction": {
        "type": "object",
        "description": "A Zavu Function — user-supplied TypeScript that runs in Zavu Cloud and reacts to messaging events or HTTP requests.",
        "required": [
          "id",
          "slug",
          "name",
          "runtime",
          "status",
          "timeoutSec",
          "memoryMb",
          "httpEnabled",
          "dependencies",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "fn_abc123"
          },
          "slug": {
            "type": "string",
            "description": "URL-safe identifier, unique per project.",
            "example": "order-bot"
          },
          "name": {
            "type": "string",
            "example": "Order Bot"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "runtime": {
            "$ref": "#/components/schemas/ZavuFunctionRuntime"
          },
          "status": {
            "$ref": "#/components/schemas/ZavuFunctionStatus"
          },
          "timeoutSec": {
            "type": "integer",
            "description": "Per-invocation timeout in seconds.",
            "example": 10
          },
          "memoryMb": {
            "type": "integer",
            "description": "Memory allocation in MB.",
            "example": 256
          },
          "httpEnabled": {
            "type": "boolean",
            "description": "Whether the function can be invoked over HTTPS via its public URL."
          },
          "publicUrl": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "HTTPS endpoint, present only while httpEnabled is true. Null otherwise, including for a function that was previously exposed — the stored URL stops serving the moment HTTP is turned off, so it is never returned."
          },
          "dependencies": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "npm dependencies installed in the function bundle. Keys are package names, values are semver ranges.",
            "example": {
              "openai": "^4.20.0"
            }
          },
          "activeDeploymentId": {
            "type": "string",
            "nullable": true,
            "description": "ID of the deployment currently serving traffic."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ZavuFunctionResponse": {
        "type": "object",
        "required": [
          "function"
        ],
        "properties": {
          "function": {
            "$ref": "#/components/schemas/ZavuFunction"
          }
        }
      },
      "FunctionCreateRequest": {
        "type": "object",
        "required": [
          "slug",
          "name"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "description": "URL-safe identifier (lowercase, digits, hyphens). Must be unique per project.",
            "minLength": 1,
            "maxLength": 50,
            "example": "order-bot"
          },
          "name": {
            "type": "string",
            "maxLength": 80,
            "example": "Order Bot"
          },
          "description": {
            "type": "string",
            "maxLength": 280
          },
          "runtime": {
            "$ref": "#/components/schemas/ZavuFunctionRuntime"
          },
          "timeoutSec": {
            "type": "integer",
            "minimum": 1,
            "maximum": 180,
            "default": 30,
            "description": "Per-invocation timeout in seconds. Event and cron invocations are asynchronous, so a long timeout only bounds cost; a tool called during a live conversation holds up the reply, and a function exposed over HTTP is additionally bounded by the platform's HTTP response limit."
          },
          "memoryMb": {
            "type": "integer",
            "enum": [
              128,
              256,
              512,
              1024
            ],
            "default": 256
          },
          "httpEnabled": {
            "type": "boolean",
            "default": false,
            "description": "Whether to expose a public HTTPS URL for this function."
          },
          "sourceCode": {
            "type": "string",
            "description": "TypeScript source code for the function entry point (max ~900KB).",
            "maxLength": 900000
          },
          "dependencies": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "npm dependencies. Keys are package names, values are semver ranges.",
            "example": {
              "openai": "^4.20.0"
            }
          }
        }
      },
      "FunctionDeployRequest": {
        "type": "object",
        "description": "Optional source/dependencies update applied before deploying. Omit both fields to redeploy the current draft as-is.",
        "properties": {
          "sourceCode": {
            "type": "string",
            "description": "New source code to publish (replaces the draft).",
            "maxLength": 900000
          },
          "dependencies": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "New dependency map (replaces existing dependencies)."
          }
        }
      },
      "FunctionDeploymentStatus": {
        "type": "string",
        "description": "Stage of a function deployment.",
        "enum": [
          "pending",
          "bundling",
          "uploading",
          "publishing",
          "active",
          "failed",
          "superseded"
        ]
      },
      "FunctionDeployment": {
        "type": "object",
        "required": [
          "id",
          "functionId",
          "version",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "fnd_abc123"
          },
          "functionId": {
            "type": "string"
          },
          "version": {
            "type": "integer",
            "description": "Monotonically increasing deployment version, starting at 1."
          },
          "status": {
            "$ref": "#/components/schemas/FunctionDeploymentStatus"
          },
          "sourceCodeBytes": {
            "type": "integer",
            "nullable": true
          },
          "bundleBytes": {
            "type": "integer",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true,
            "description": "Failure reason when status is 'failed'."
          },
          "deployedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FunctionDeploymentResponse": {
        "type": "object",
        "required": [
          "deployment"
        ],
        "properties": {
          "deployment": {
            "$ref": "#/components/schemas/FunctionDeployment"
          }
        }
      },
      "FunctionLogEvent": {
        "type": "object",
        "required": [
          "timestamp",
          "message"
        ],
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "FunctionLogsResponse": {
        "type": "object",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunctionLogEvent"
            }
          },
          "nextToken": {
            "type": "string",
            "nullable": true,
            "description": "Pass to the next request to fetch the following page of logs."
          }
        }
      },
      "GitRepoLink": {
        "type": "object",
        "description": "A GitHub repository bound to a function. A push to `branch` deploys the function. A function holds at most one link.",
        "required": [
          "id",
          "functionId",
          "provider",
          "owner",
          "repo",
          "branch",
          "autoDeploy",
          "connection",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "functionId": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "github"
            ]
          },
          "owner": {
            "type": "string",
            "example": "acme"
          },
          "repo": {
            "type": "string",
            "example": "order-bot"
          },
          "branch": {
            "type": "string",
            "description": "Only pushes to this branch deploy.",
            "example": "main"
          },
          "rootDir": {
            "type": "string",
            "nullable": true,
            "description": "Subdirectory holding the project, for monorepos. Null when the project is at the repository root."
          },
          "autoDeploy": {
            "type": "boolean",
            "description": "When false the link is kept and pushes are ignored."
          },
          "connection": {
            "type": "string",
            "description": "How this link authenticates, decided by the server rather than by the caller.\n- `app`: the Zavu GitHub App is installed on the account. Pushes arrive on the app's webhook and private repositories work. Nothing to configure in the repository.\n- `manual`: no installation. The link carries its own secret and you add the webhook to the repository yourself.",
            "enum": [
              "app",
              "manual"
            ]
          },
          "lastStatus": {
            "type": "string",
            "nullable": true,
            "enum": [
              "deploying",
              "deployed",
              "failed",
              null
            ]
          },
          "lastCommitSha": {
            "type": "string",
            "nullable": true
          },
          "lastCommitMessage": {
            "type": "string",
            "nullable": true
          },
          "lastError": {
            "type": "string",
            "nullable": true,
            "description": "Why the last deploy failed. Null otherwise."
          },
          "lastDeployAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GitRepoLinkResponse": {
        "type": "object",
        "required": [
          "link",
          "webhookUrl"
        ],
        "properties": {
          "link": {
            "$ref": "#/components/schemas/GitRepoLink"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "description": "Endpoint that receives GitHub's push deliveries. Only needed on a `manual` link, where you add it to the repository yourself."
          },
          "webhookSecret": {
            "type": "string",
            "description": "Shared secret for the repository's webhook. **Returned only when creating a `manual` link, and only there** — every later read strips it, and re-linking mints a new one. Absent entirely on an `app` link, which needs no secret of its own.",
            "example": "ghs_a1b2c3..."
          }
        }
      },
      "AgentVoiceConfig": {
        "type": "object",
        "description": "Voice Agent configuration on a sender's AI agent. Controls how the agent behaves on inbound and outbound phone calls through Zavu's managed voice pipeline (speech recognition, the agent's LLM, and speech synthesis, with real-time interruption handling). Requires the Voice Agents feature to be enabled for your team.",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the agent handles voice calls. When false, the sender's number is not answered by the voice agent and outbound calls are rejected."
          },
          "greeting": {
            "type": "string",
            "description": "Opening line the agent speaks when the call connects. If omitted, the agent waits for the caller to speak first.",
            "maxLength": 1000,
            "example": "Hi, thanks for calling Acme. How can I help you today?"
          },
          "greetings": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Greeting per language, keyed by language code. Used when the caller's language differs from the one `greeting` is written in.",
            "example": {
              "es": "Hola, soy Atlas. Preguntame lo que quieras."
            }
          },
          "language": {
            "type": "string",
            "description": "BCP-47 language code used for both speech recognition and speech synthesis (e.g. `en`, `es`, `pt-BR`). Auto-detected from the recipient when omitted.",
            "example": "en"
          },
          "model": {
            "type": "string",
            "description": "Model that runs the conversation, co-located in the voice network for lowest latency. Independent of the model used for text messaging. Derived from the agent's text model when omitted.",
            "example": "openai/gpt-4o"
          },
          "sttProvider": {
            "type": "string",
            "description": "Speech-recognition provider. Uses the default when omitted."
          },
          "sttModel": {
            "type": "string",
            "description": "Speech-recognition model. Uses the default when omitted."
          },
          "ttsProvider": {
            "type": "string",
            "description": "Speech-synthesis provider. Uses the default when omitted."
          },
          "ttsVoiceId": {
            "type": "string",
            "description": "Identifier of the synthesized voice that speaks. Choose from the voices available in the dashboard. Uses a neutral default when omitted.",
            "example": "aria"
          },
          "voiceSpeed": {
            "type": "number",
            "description": "Speech rate. 1.0 is natural. Only honoured by voices that support rate control; ignored by the others.",
            "minimum": 0.5,
            "maximum": 1.5,
            "default": 1.0
          },
          "interruptible": {
            "type": "boolean",
            "description": "Whether the caller can interrupt the agent while it is speaking (barge-in). When true, the agent stops talking as soon as the caller starts.",
            "default": true
          },
          "maxCallDurationMinutes": {
            "type": "integer",
            "description": "Hard limit on call length in minutes. The call ends automatically when reached.",
            "minimum": 1,
            "maximum": 120,
            "default": 15
          },
          "maxIdleSeconds": {
            "type": "integer",
            "description": "How long the agent waits during silence before ending the call.",
            "minimum": 5,
            "maximum": 300,
            "default": 30
          },
          "recordCalls": {
            "type": "boolean",
            "description": "Whether the call audio is recorded."
          },
          "voicemailAction": {
            "type": "string",
            "description": "What the agent does when an answering machine or voicemail is detected on an outbound call.",
            "enum": [
              "hangup",
              "leave_message"
            ],
            "default": "hangup"
          },
          "voicemailMessage": {
            "type": "string",
            "description": "Message spoken when `voicemailAction` is `leave_message`. Falls back to `greeting` when omitted.",
            "maxLength": 1000
          },
          "transferPhoneNumber": {
            "type": "string",
            "description": "E.164 phone number the agent can transfer the call to. When set, the agent is given a transfer tool it can use to hand the call to a human.",
            "example": "+14155551234"
          }
        }
      },
      "VoiceCall": {
        "type": "object",
        "required": [
          "id",
          "direction",
          "from",
          "to",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "call_abc123"
          },
          "direction": {
            "$ref": "#/components/schemas/VoiceCallDirection"
          },
          "from": {
            "type": "string",
            "description": "Caller phone number in E.164 format. Your sender's number for outbound calls; the caller's number for inbound calls.",
            "example": "+13125551212"
          },
          "to": {
            "type": "string",
            "description": "Callee phone number in E.164 format.",
            "example": "+56912345678"
          },
          "status": {
            "$ref": "#/components/schemas/VoiceCallStatus"
          },
          "endReason": {
            "type": "string",
            "nullable": true,
            "description": "Why the call ended (e.g. `agent_ended`, `max_duration`, `transfer`, `hangup`). Present once the call is no longer active."
          },
          "answeredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the call was answered."
          },
          "endedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the call ended."
          },
          "durationSeconds": {
            "type": "integer",
            "nullable": true,
            "description": "Billable talk time in seconds, measured from answer to hangup."
          },
          "turnCount": {
            "type": "integer",
            "nullable": true,
            "description": "Number of conversation turns exchanged during the call."
          },
          "transcript": {
            "type": "array",
            "description": "Ordered transcript of the call. Included when retrieving a single call; omitted from list responses.",
            "items": {
              "$ref": "#/components/schemas/VoiceCallTurn"
            }
          },
          "cost": {
            "type": "number",
            "nullable": true,
            "description": "Total cost of the call in USD, combining the managed voice pipeline per-minute charge and telephony. Available once the call has ended."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Arbitrary metadata you attached when creating the call."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "VoiceCallCreateRequest": {
        "type": "object",
        "description": "Request body to place an outbound voice call. The call is answered by the voice agent configured on the sender.",
        "required": [
          "to"
        ],
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient phone number in E.164 format.",
            "example": "+56912345678"
          },
          "senderId": {
            "type": "string",
            "description": "Sender profile that places the call. Uses the project's default sender if omitted. The sender's agent must have voice enabled.",
            "example": "sender_12345"
          },
          "greeting": {
            "type": "string",
            "description": "Overrides the agent's configured greeting for this call only.",
            "maxLength": 1000
          },
          "language": {
            "type": "string",
            "description": "Language the agent speaks on this call only, as a BCP-47 tag (`en`, `es`, `es-ES`, `pt-BR`), or `auto` to detect the caller's language and follow it. Overrides the agent's configured language for speech recognition, the agent's replies, and the synthesized voice. If the agent uses a custom voice you supplied, that voice is kept and only the language changes. When omitted, the agent's configured language is used.",
            "maxLength": 15,
            "example": "es-ES"
          },
          "maxDurationMinutes": {
            "type": "integer",
            "description": "Overrides the agent's maximum call duration for this call only.",
            "minimum": 1,
            "maximum": 120
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Arbitrary metadata to associate with the call. Returned on the call object and included in voice webhooks."
          }
        }
      },
      "VoiceCallDirection": {
        "type": "string",
        "description": "Whether the call was placed by Zavu (outbound) or received from a caller (inbound).",
        "enum": [
          "inbound",
          "outbound"
        ]
      },
      "VoiceCallResponse": {
        "type": "object",
        "required": [
          "call"
        ],
        "properties": {
          "call": {
            "$ref": "#/components/schemas/VoiceCall"
          }
        }
      },
      "VoiceCallStatus": {
        "type": "string",
        "description": "Lifecycle status of a voice call.\n- `queued`: outbound call created, not yet dialing.\n- `ringing`: dialing (outbound) or received and ringing (inbound).\n- `in_progress`: answered, the agent is connected.\n- `completed`: ended after a conversation.\n- `failed`: could not be completed.\n- `busy`: the line was busy.\n- `no_answer`: rang but was not answered.\n- `canceled`: canceled before it was answered.",
        "enum": [
          "queued",
          "ringing",
          "in_progress",
          "completed",
          "failed",
          "busy",
          "no_answer",
          "canceled"
        ]
      },
      "VoiceCallTurn": {
        "type": "object",
        "description": "A single turn in a voice call transcript.",
        "required": [
          "seq",
          "role",
          "text"
        ],
        "properties": {
          "seq": {
            "type": "integer",
            "description": "Ordinal position of the turn within the call, starting at 0."
          },
          "role": {
            "type": "string",
            "description": "Who produced the turn. `tool` records a tool call the agent made during the conversation.",
            "enum": [
              "user",
              "assistant",
              "tool"
            ]
          },
          "text": {
            "type": "string",
            "description": "Transcribed speech for `user` and `assistant` turns, or a JSON summary of the tool call for `tool` turns."
          },
          "startedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the turn started."
          },
          "endedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the turn ended."
          }
        }
      },
      "AgentTemplate": {
        "type": "object",
        "description": "A fully rendered factory agent: the function files to scaffold plus the secrets it needs. Returned by GET /v1/agent-templates/{templateId} and consumed by `npx zavudev agents pull`.",
        "required": [
          "id",
          "name",
          "summary",
          "category",
          "voice",
          "defaultSlug",
          "files",
          "dependencies",
          "requiredSecrets"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "fermi"
          },
          "name": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "enum": [
              "sales",
              "support",
              "frontDesk",
              "ops"
            ]
          },
          "voice": {
            "type": "boolean"
          },
          "defaultSlug": {
            "type": "string",
            "example": "fermi"
          },
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentTemplateFile"
            }
          },
          "dependencies": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "npm dependencies for the scaffolded function."
          },
          "requiredSecrets": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "hint"
              ],
              "properties": {
                "key": {
                  "type": "string",
                  "example": "SENDER_ID"
                },
                "hint": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "AgentTemplateFile": {
        "type": "object",
        "required": [
          "path",
          "content"
        ],
        "properties": {
          "path": {
            "type": "string",
            "example": "index.ts"
          },
          "content": {
            "type": "string",
            "description": "File contents to write verbatim."
          }
        }
      },
      "AgentTemplateSummary": {
        "type": "object",
        "description": "Compact catalog entry for a factory agent.",
        "required": [
          "id",
          "name",
          "summary",
          "category",
          "voice",
          "toolCount"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "fermi"
          },
          "name": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "enum": [
              "sales",
              "support",
              "frontDesk",
              "ops"
            ]
          },
          "voice": {
            "type": "boolean",
            "description": "Whether this agent answers phone calls."
          },
          "toolCount": {
            "type": "integer"
          }
        }
      },
      "EmailDomain": {
        "type": "object",
        "required": [
          "id",
          "domain",
          "status",
          "dkimStatus"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "emd_abc123"
          },
          "domain": {
            "type": "string",
            "example": "example.com"
          },
          "status": {
            "type": "string",
            "description": "Overall verification status.",
            "example": "pending"
          },
          "dkimStatus": {
            "type": "string",
            "example": "not_started"
          },
          "dnsRecords": {
            "type": "array",
            "description": "DNS records to publish. Present when fetching a single domain or after adding one.",
            "items": {
              "$ref": "#/components/schemas/EmailDomainDnsRecord"
            }
          }
        }
      },
      "EmailDomainDnsRecord": {
        "type": "object",
        "required": [
          "type",
          "name",
          "value",
          "purpose",
          "required"
        ],
        "properties": {
          "type": {
            "type": "string",
            "description": "DNS record type.",
            "example": "CNAME"
          },
          "name": {
            "type": "string",
            "description": "Record host/name to create."
          },
          "value": {
            "type": "string",
            "description": "Record value."
          },
          "priority": {
            "type": "integer",
            "description": "Priority (MX records only)."
          },
          "purpose": {
            "type": "string",
            "description": "What the record is for.",
            "enum": [
              "dkim",
              "spf",
              "dmarc",
              "mail_from"
            ]
          },
          "required": {
            "type": "boolean",
            "description": "Whether the record is required to verify + send (DKIM) or recommended for deliverability."
          }
        }
      },
      "AgentTestRequest": {
        "type": "object",
        "description": "Run the agent and return what it would say. Nothing is delivered to anyone, no execution is recorded, and nothing is charged.",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "What to say to the agent.",
            "example": "Where is order ORD-12345?"
          },
          "history": {
            "type": "array",
            "description": "Prior turns, oldest first, to exercise multi-turn behaviour without persisting a thread. Trimmed to the agent's context window.",
            "items": {
              "type": "object",
              "required": [
                "role",
                "content"
              ],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": [
                    "user",
                    "assistant"
                  ]
                },
                "content": {
                  "type": "string"
                }
              }
            }
          },
          "useKnowledgeBase": {
            "type": "boolean",
            "default": true,
            "description": "Set false to skip retrieval and isolate prompt behaviour from the knowledge base."
          }
        }
      },
      "AgentTestResponse": {
        "type": "object",
        "required": [
          "success",
          "text",
          "error",
          "inputTokens",
          "outputTokens",
          "latencyMs",
          "knowledgeChunksUsed",
          "warnings"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "text": {
            "type": "string",
            "nullable": true,
            "description": "What the agent would reply."
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "inputTokens": {
            "type": "integer"
          },
          "outputTokens": {
            "type": "integer"
          },
          "latencyMs": {
            "type": "integer"
          },
          "knowledgeChunksUsed": {
            "type": "integer",
            "description": "Knowledge-base chunks retrieved for this message. Zero means the answer was not grounded in your documents."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Things that are true of this agent but that a dry run cannot prove. Surfaced so a passing dry run is never mistaken for proof that the agent works live.\n\n- The agent being disabled.\n- Enabled tools that were **not offered to the model** here — the model never saw them, so a reply that looks like a lookup was invented. Live conversations on every channel do offer them; running them here would cause real side effects.\n- An agent whose sender has none of the channels it triggers on, which answers every dry run and no real message.\n- Contact metadata that exists on a real conversation but not here."
          }
        }
      },
      "AgentCreateStandaloneRequest": {
        "type": "object",
        "description": "Create an agent that exists on its own. Connect senders afterwards; an agent answers on any number of them.\n\n**Sub-resources.** An agent's tools, flows and knowledge bases are reachable at `/v1/agents/{agentId}/tools`, `/v1/agents/{agentId}/flows` and `/v1/agents/{agentId}/knowledge-bases`, mirroring the sender-scoped routes documented under `/v1/senders/{senderId}/agent/...` exactly. Use the agent-scoped form while the agent has no sender: the sender-scoped one cannot address it.",
        "required": [
          "name",
          "provider",
          "model",
          "systemPrompt"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100
          },
          "provider": {
            "$ref": "#/components/schemas/AgentProvider"
          },
          "model": {
            "type": "string"
          },
          "systemPrompt": {
            "type": "string",
            "maxLength": 10000
          },
          "contextWindowMessages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 10
          },
          "includeContactMetadata": {
            "type": "boolean",
            "default": true
          },
          "triggerOnChannels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": [
              "*"
            ]
          },
          "triggerOnMessageTypes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "default": [
              "text"
            ]
          },
          "maxTokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 4096
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2
          },
          "voice": {
            "$ref": "#/components/schemas/AgentVoiceConfig"
          }
        }
      },
      "FunctionUpdateRequest": {
        "type": "object",
        "description": "Fields to update on an existing function. Provide at least one. `sourceCode` and `dependencies` edit the draft and take effect on the next deploy; `httpEnabled` applies immediately to the deployed function.",
        "properties": {
          "sourceCode": {
            "type": "string",
            "description": "New source code for the draft (replaces it).",
            "maxLength": 900000
          },
          "dependencies": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "New dependency map (replaces existing dependencies)."
          },
          "httpEnabled": {
            "type": "boolean",
            "description": "Expose the function on its public HTTPS URL, or take it down. Applies to the already-deployed function without redeploying; the URL is returned as `publicUrl`."
          }
        }
      },
      "WebhookSignatureVersion": {
        "type": "string",
        "description": "Which `X-Zavu-Signature` scheme this receiver is sent.\n\n- `v1`: `v1=HMAC_SHA256(secret, body)`. The scheme used before this was configurable. Existing webhooks stay on it until you move them.\n- `v2`: `v2=HMAC_SHA256(secret, \"{t}.{body}\")`. The current scheme, and the default for new senders. It signs the timestamp together with the body.\n- `v1+v2`: both signatures, sharing one `t`. The migration setting: a receiver reading either one works, so you can deploy and confirm your new verifier before switching over.\n\nMoving from `v1` straight to `v2` returns `400`. Set `v1+v2` first. See https://docs.zavu.dev/guides/receiving-messages/signature-migration",
        "enum": [
          "v1",
          "v1+v2",
          "v2"
        ],
        "example": "v2"
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/functions/event-types": {
      "get": {
        "summary": "List function event types",
        "description": "List the event types a function trigger can subscribe to. Includes the special type `cron`, which fires on a schedule (see POST /v1/functions/{functionId}/triggers) rather than on a messaging event.",
        "operationId": "listFunctionEventTypes",
        "tags": [
          "Functions"
        ],
        "responses": {
          "200": {
            "description": "Supported event types.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "events"
                  ],
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "example": [
                        "message.inbound",
                        "message.delivered",
                        "cron"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/triggers": {
      "get": {
        "summary": "List function triggers",
        "operationId": "listFunctionTriggers",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Triggers for the function.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "triggers"
                  ],
                  "properties": {
                    "triggers": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FunctionTrigger"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create function triggers",
        "description": "Subscribe a function to one or more event types, optionally scoped to specific senders. Provide eventTypes and senderIds (use null in senderIds for all senders); a trigger is created for each event type and sender combination.\n\nThe special event type `cron` runs the function on a schedule instead of a messaging event: include a `cron` field with a 5-field UTC cron expression (minimum granularity one minute). A cron trigger ignores the sender axis, and a function may hold several cron triggers with different expressions. The function receives an event with `type: \"cron\"` and `data.cron`.",
        "operationId": "createFunctionTriggers",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "eventTypes",
                  "senderIds"
                ],
                "properties": {
                  "eventTypes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Event types to subscribe to."
                  },
                  "senderIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "nullable": true
                    },
                    "description": "Senders to scope the triggers to. Use null for all senders."
                  },
                  "cron": {
                    "type": "string",
                    "description": "Required when eventTypes includes `cron`: a 5-field cron expression (minute hour day-of-month month day-of-week), evaluated in UTC.",
                    "example": "0 9 * * 1-5"
                  }
                }
              },
              "example": {
                "eventTypes": [
                  "message.inbound"
                ],
                "senderIds": [
                  null
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Triggers created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "added",
                    "skipped",
                    "triggers"
                  ],
                  "properties": {
                    "added": {
                      "type": "integer"
                    },
                    "skipped": {
                      "type": "integer",
                      "description": "Number of triggers that already existed."
                    },
                    "triggers": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FunctionTrigger"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/triggers/{triggerId}": {
      "patch": {
        "summary": "Enable or disable a trigger",
        "operationId": "updateFunctionTrigger",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "name": "triggerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "active"
                ],
                "properties": {
                  "active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Trigger updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "active"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "active": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Trigger not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete a trigger",
        "operationId": "deleteFunctionTrigger",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "name": "triggerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Trigger deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Trigger not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/deployments": {
      "get": {
        "summary": "List function deployments",
        "description": "List a function's deployment history, newest first. Source code is omitted; fetch a single deployment via GET /v1/functions/deployments/{deploymentId} for full details.",
        "operationId": "listFunctionDeployments",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deployment history.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deployments"
                  ],
                  "properties": {
                    "deployments": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "version": {
                            "type": "integer"
                          },
                          "status": {
                            "$ref": "#/components/schemas/FunctionDeploymentStatus"
                          },
                          "bundleSizeBytes": {
                            "type": "integer",
                            "nullable": true
                          },
                          "errorMessage": {
                            "type": "string",
                            "nullable": true
                          },
                          "isActive": {
                            "type": "boolean"
                          },
                          "deployedAt": {
                            "type": "string",
                            "format": "date-time",
                            "nullable": true
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/rollback": {
      "post": {
        "summary": "Roll back to a previous deployment",
        "description": "Re-deploy a previous version by copying its source, dependencies, and runtime pin onto the function's draft, then deploying. Returns immediately with a deployment ID — poll GET /v1/functions/deployments/{deploymentId} until status is active or failed. Secrets are not rolled back.",
        "operationId": "rollbackFunction",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "deploymentId"
                ],
                "properties": {
                  "deploymentId": {
                    "type": "string",
                    "description": "ID of the deployment to roll back to."
                  }
                }
              },
              "example": {
                "deploymentId": "fnd_abc123"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Rollback deployment queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deployment"
                  ],
                  "properties": {
                    "deployment": {
                      "$ref": "#/components/schemas/FunctionDeployment"
                    },
                    "rolledBackToVersion": {
                      "type": "integer"
                    },
                    "previousDraft": {
                      "type": "object",
                      "nullable": true,
                      "description": "The draft that was replaced, so a UI can offer to restore it."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or function in a non-deployable state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function or deployment not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/urls/{urlId}/escalate": {
      "post": {
        "summary": "Escalate a rejected URL",
        "description": "Request manual review of a rejected URL. Only URLs in 'rejected' status can be escalated; the status then moves to 'escalated'.",
        "operationId": "escalateUrl",
        "tags": [
          "URL Verification"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UrlIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "reason"
                ],
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 1000,
                    "description": "Why the URL should be reviewed manually."
                  }
                }
              },
              "example": {
                "reason": "This is our official landing page and was rejected in error."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "URL escalated for manual review.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url",
                    "message"
                  ],
                  "properties": {
                    "url": {
                      "$ref": "#/components/schemas/VerifiedUrl"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Only rejected URLs can be escalated, or the URL is already escalated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "URL not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/messages": {
      "post": {
        "summary": "Send a message",
        "description": "Send a message to a recipient via SMS or WhatsApp.\n\n**Channel selection:**\n- If `channel` is omitted and `messageType` is `text`, defaults to SMS\n- If `messageType` is anything other than `text`, WhatsApp is used automatically\n\n**WhatsApp 24-hour window:**\n- Free-form messages (non-template) require an open 24h window\n- Window opens when the user messages you first\n- Use template messages to initiate conversations outside the window\n\n**Plan allowances and email billing:**\n- WhatsApp, Telegram, Instagram and Messenger share an allowance of 2,000 messages per month on Free. Over it, sends return 429 with code `a2p_limit_exceeded` and upgrade details; the counter resets on the 1st of each month. Paid plans have no message caps\n- Email is billed from your prepaid balance in 1,000-message blocks: $0.40 per 1,000 transactional emails, $0.80 per 1,000 marketing (broadcast) emails. A block is charged when your monthly count crosses each 1,000 boundary, and at zero balance email sends return 402 with code `insufficient_balance`. Free teams start with $2 of credit and additionally cap at 3,000 emails/month and 100/day. Teams on earlier plans keep their original email quotas instead\n- SMS and voice are billed per message from your balance on every plan\n\n**Email recipient pre-flight:**\nEmail messages are validated automatically before dispatch. Sends that would be a guaranteed hard bounce are failed instead of sent, protecting your bounce rate: the message transitions to `failed` (visible via `GET /v1/messages/{messageId}` and the `message.failed` webhook) with `errorCode` set to `EMAIL_INVALID_RECIPIENT` (malformed address), `EMAIL_DOMAIN_NOT_FOUND` (recipient domain has no MX or A records), or `EMAIL_RECIPIENT_SUPPRESSED` (address is on your suppression list after a previous bounce or complaint). Advisory signals (role addresses, disposable domains) do not block sends — check them beforehand with `POST /v1/introspect/email`.",
        "operationId": "sendMessage",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageRequest"
              },
              "examples": {
                "sms": {
                  "summary": "Simple SMS",
                  "value": {
                    "to": "+56912345678",
                    "text": "Your verification code is 123456"
                  }
                },
                "whatsapp_text": {
                  "summary": "WhatsApp text message",
                  "value": {
                    "to": "+56912345678",
                    "channel": "whatsapp",
                    "text": "Hello from Zavu!"
                  }
                },
                "whatsapp_image": {
                  "summary": "WhatsApp image",
                  "value": {
                    "to": "+56912345678",
                    "messageType": "image",
                    "text": "Check out this product!",
                    "content": {
                      "mediaUrl": "https://example.com/product.jpg"
                    }
                  }
                },
                "whatsapp_buttons": {
                  "summary": "WhatsApp interactive buttons",
                  "value": {
                    "to": "+56912345678",
                    "messageType": "buttons",
                    "text": "How would you rate your experience?",
                    "content": {
                      "buttons": [
                        {
                          "id": "great",
                          "title": "Great!"
                        },
                        {
                          "id": "okay",
                          "title": "It was okay"
                        },
                        {
                          "id": "poor",
                          "title": "Not good"
                        }
                      ]
                    }
                  }
                },
                "whatsapp_template": {
                  "summary": "WhatsApp template message",
                  "value": {
                    "to": "+56912345678",
                    "messageType": "template",
                    "content": {
                      "templateId": "tmpl_abc123",
                      "templateVariables": {
                        "1": "John",
                        "2": "ORD-12345"
                      }
                    }
                  }
                },
                "whatsapp_template_with_url_button": {
                  "summary": "WhatsApp template with dynamic URL button",
                  "value": {
                    "to": "+56912345678",
                    "messageType": "template",
                    "content": {
                      "templateId": "tmpl_abc123",
                      "templateVariables": {
                        "1": "ORDAZ BRAVO MARCO",
                        "2": "REPORTE: Conducta inadecuada"
                      },
                      "templateButtonVariables": {
                        "0": "abc-report-token"
                      }
                    }
                  }
                },
                "whatsapp_cta_url": {
                  "summary": "WhatsApp CTA URL button",
                  "value": {
                    "to": "+56912345678",
                    "channel": "whatsapp",
                    "messageType": "cta_url",
                    "text": "Tap the button below to see available dates.",
                    "content": {
                      "ctaDisplayText": "See Dates",
                      "ctaUrl": "https://example.com/schedule?ref=zavu",
                      "ctaHeaderType": "image",
                      "ctaHeaderMediaUrl": "https://example.com/banner.png",
                      "footerText": "Dates subject to change."
                    }
                  }
                },
                "whatsapp_location_request": {
                  "summary": "WhatsApp location request",
                  "value": {
                    "to": "+56912345678",
                    "channel": "whatsapp",
                    "messageType": "location_request",
                    "text": "To finish your order, share the delivery address."
                  }
                },
                "whatsapp_request_contact_info": {
                  "summary": "WhatsApp contact info request (ask for phone number)",
                  "value": {
                    "to": "US.13491208655302741918",
                    "channel": "whatsapp",
                    "messageType": "request_contact_info",
                    "text": "Share your phone number so our team can call you back."
                  }
                },
                "whatsapp_to_bsuid": {
                  "summary": "WhatsApp message to a BSUID (username contact)",
                  "value": {
                    "to": "US.13491208655302741918",
                    "channel": "whatsapp",
                    "text": "Thanks for reaching out! How can we help?"
                  }
                },
                "telegram_text": {
                  "summary": "Telegram text message",
                  "value": {
                    "to": "123456789",
                    "channel": "telegram",
                    "text": "Hello from Zavu via Telegram!"
                  }
                },
                "telegram_template": {
                  "summary": "Telegram template message",
                  "value": {
                    "to": "123456789",
                    "channel": "telegram",
                    "messageType": "template",
                    "content": {
                      "templateId": "tmpl_abc123",
                      "templateVariables": {
                        "1": "John",
                        "2": "ORD-12345"
                      }
                    }
                  }
                },
                "sms_template": {
                  "summary": "SMS template message",
                  "value": {
                    "to": "+56912345678",
                    "channel": "sms",
                    "messageType": "template",
                    "content": {
                      "templateId": "tmpl_abc123",
                      "templateVariables": {
                        "1": "John",
                        "2": "ORD-12345"
                      }
                    }
                  }
                },
                "instagram_text": {
                  "summary": "Instagram text message",
                  "value": {
                    "to": "17841400000000000",
                    "channel": "instagram",
                    "text": "Hello from Zavu via Instagram!"
                  }
                },
                "messenger_text": {
                  "summary": "Messenger text message (Facebook Page / Marketplace chat)",
                  "value": {
                    "to": "24025631120151183",
                    "channel": "messenger",
                    "text": "Hello from Zavu via Messenger!"
                  }
                },
                "voice_tts": {
                  "summary": "Voice text-to-speech message",
                  "value": {
                    "to": "+56912345678",
                    "channel": "voice",
                    "text": "Your verification code is 1 2 3 4 5 6"
                  }
                },
                "voice_tts_spanish": {
                  "summary": "Voice TTS in Spanish",
                  "value": {
                    "to": "+56912345678",
                    "channel": "voice",
                    "text": "Su codigo de verificacion es 1 2 3 4 5 6",
                    "voiceLanguage": "es-ES"
                  }
                },
                "email_simple": {
                  "summary": "Simple email",
                  "value": {
                    "to": "user@example.com",
                    "channel": "email",
                    "subject": "Your order has shipped",
                    "text": "Hi John, your order #12345 has shipped and will arrive in 2-3 business days."
                  }
                },
                "email_html": {
                  "summary": "Email with HTML body",
                  "value": {
                    "to": "user@example.com",
                    "channel": "email",
                    "subject": "Welcome to Zavu",
                    "text": "Welcome to Zavu! We're excited to have you.",
                    "htmlBody": "<h1>Welcome to Zavu!</h1><p>We're excited to have you on board.</p>",
                    "replyTo": "support@example.com"
                  }
                },
                "email_attachment": {
                  "summary": "Email with attachments",
                  "value": {
                    "to": "user@example.com",
                    "channel": "email",
                    "subject": "Your invoice",
                    "text": "Please find your invoice attached.",
                    "attachments": [
                      {
                        "filename": "invoice.pdf",
                        "content": "JVBERi0xLjQK...",
                        "content_type": "application/pdf"
                      }
                    ]
                  }
                },
                "email_inline_image": {
                  "summary": "Email with inline image",
                  "value": {
                    "to": "user@example.com",
                    "channel": "email",
                    "subject": "Your report",
                    "text": "See your report below.",
                    "htmlBody": "<h1>Report</h1><img src=\"cid:chart\"><p>Details above.</p>",
                    "attachments": [
                      {
                        "filename": "chart.png",
                        "path": "https://example.com/chart.png",
                        "content_type": "image/png",
                        "content_id": "chart"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Message accepted for delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or WhatsApp 24h window not open.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "window_closed": {
                    "summary": "WhatsApp window closed",
                    "value": {
                      "code": "whatsapp_window_closed",
                      "message": "WhatsApp 24-hour window is not open. Use a template message or wait for user to message first."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance. Email is billed from your prepaid balance in 1,000-message blocks; SMS and voice are billed per message. When the balance cannot cover the send, the message is rejected until you add funds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "insufficient_balance",
                  "message": "Insufficient balance to send email. Add funds from the dashboard to resume."
                }
              }
            }
          },
          "403": {
            "description": "Message blocked due to URL restrictions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "url_not_verified": {
                    "summary": "URL not verified",
                    "value": {
                      "code": "url_not_verified",
                      "message": "Message blocked: Contains unverified URLs. Submit URLs for verification via the /v1/urls endpoint.",
                      "details": {
                        "urls": [
                          "https://example.com"
                        ],
                        "submissionEndpoint": "/v1/urls"
                      }
                    }
                  },
                  "url_shortener_blocked": {
                    "summary": "URL shortener blocked",
                    "value": {
                      "code": "url_shortener_blocked",
                      "message": "Message blocked: URL shorteners are not allowed. Please use the full destination URL.",
                      "details": {
                        "blockedUrls": [
                          "https://bit.ly/abc123"
                        ],
                        "reason": "url_shorteners_hidden_destination"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Template or sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict (message already sent).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List messages",
        "description": "List messages previously sent by this project.",
        "operationId": "listMessages",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filter by status. Not all stored statuses are filterable.",
            "schema": {
              "type": "string",
              "enum": [
                "queued",
                "sending",
                "sent",
                "delivered",
                "failed",
                "received"
              ]
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel",
            "in": "query",
            "description": "Filter by delivery channel.",
            "schema": {
              "type": "string",
              "enum": [
                "sms",
                "sms_oneway",
                "whatsapp",
                "email",
                "telegram",
                "instagram",
                "messenger",
                "voice"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of messages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Message"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/messages/{messageId}": {
      "get": {
        "summary": "Get message by ID",
        "operationId": "getMessage",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Message details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/messages/{messageId}/reactions": {
      "post": {
        "summary": "Send reaction to message",
        "description": "Send an emoji reaction to an existing WhatsApp message. Reactions are only supported for WhatsApp messages.",
        "operationId": "sendReaction",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageIdParam"
          },
          {
            "$ref": "#/components/parameters/SenderHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReactionRequest"
              },
              "example": {
                "emoji": "👍"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Reaction accepted for delivery.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or message is not from WhatsApp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "not_whatsapp": {
                    "summary": "Not a WhatsApp message",
                    "value": {
                      "code": "bad_request",
                      "message": "Reactions are only supported for WhatsApp messages"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/messages/{messageId}/typing": {
      "post": {
        "summary": "Show typing indicator",
        "description": "Mark an inbound WhatsApp message as read and display a typing indicator to the user while you prepare a response. The indicator is automatically dismissed when you send a reply, or after 25 seconds — whichever comes first. Only valid for inbound WhatsApp messages. Use this when a reply will take more than a couple of seconds (LLM agent, tool call, lookup) to improve the recipient's experience.",
        "operationId": "showTypingIndicator",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageIdParam"
          },
          {
            "$ref": "#/components/parameters/SenderHeader"
          }
        ],
        "responses": {
          "202": {
            "description": "Typing indicator displayed and message marked as read.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — message is not WhatsApp, not inbound, or has no provider message ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "not_whatsapp": {
                    "summary": "Not a WhatsApp message",
                    "value": {
                      "code": "bad_request",
                      "message": "Typing indicators are only supported for WhatsApp messages"
                    }
                  },
                  "not_inbound": {
                    "summary": "Message is not inbound",
                    "value": {
                      "code": "bad_request",
                      "message": "Typing indicators can only be sent in response to inbound messages"
                    }
                  },
                  "no_provider_id": {
                    "summary": "Missing provider message ID",
                    "value": {
                      "code": "bad_request",
                      "message": "Cannot send typing indicator: no provider message ID available"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/messages/{messageId}/attachments": {
      "get": {
        "summary": "List message attachments",
        "description": "List the stored file attachments for an email message and get a short-lived signed `downloadUrl` for each. Works for both inbound emails (received via `message.inbound`) and outbound emails you sent with attachments. Messages without stored attachments (including SMS, WhatsApp, and other channels) return an empty list. Each `downloadUrl` is generated fresh per request and expires — fetch the file promptly and do not cache the URL.",
        "operationId": "listMessageAttachments",
        "parameters": [
          {
            "$ref": "#/components/parameters/MessageIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "List of attachments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageAttachmentsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Message not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/templates": {
      "get": {
        "summary": "List templates",
        "description": "List WhatsApp message templates for this project.",
        "operationId": "listTemplates",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of templates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Template"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create template",
        "description": "Create a WhatsApp message template. Note: Templates must be approved by Meta before use.",
        "operationId": "createTemplate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateCreateRequest"
              },
              "example": {
                "name": "order_confirmation",
                "language": "en",
                "body": "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
                "whatsappCategory": "UTILITY",
                "variables": [
                  "customer_name",
                  "order_id"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "Invalid template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/templates/{templateId}": {
      "get": {
        "summary": "Get template",
        "operationId": "getTemplate",
        "parameters": [
          {
            "$ref": "#/components/parameters/TemplateIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Template details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete template",
        "operationId": "deleteTemplate",
        "parameters": [
          {
            "$ref": "#/components/parameters/TemplateIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Template deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/templates/{templateId}/submit": {
      "post": {
        "summary": "Submit template for approval",
        "description": "Submit a WhatsApp template to Meta for approval. The template must be in draft status and associated with a sender that has a WhatsApp Business Account configured.",
        "operationId": "submitTemplate",
        "parameters": [
          {
            "$ref": "#/components/parameters/TemplateIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "senderId"
                ],
                "properties": {
                  "senderId": {
                    "type": "string",
                    "description": "The sender ID with the WhatsApp Business Account to submit the template to."
                  },
                  "category": {
                    "$ref": "#/components/schemas/WhatsAppCategory",
                    "description": "Template category. If not provided, uses the category set on the template."
                  }
                }
              },
              "example": {
                "senderId": "sender_abc123",
                "category": "UTILITY"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Template submitted for approval.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or template not in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "not_draft": {
                    "summary": "Template not in draft status",
                    "value": {
                      "code": "bad_request",
                      "message": "Template is already pending approval or approved"
                    }
                  },
                  "no_waba": {
                    "summary": "Sender has no WABA",
                    "value": {
                      "code": "bad_request",
                      "message": "Sender does not have a WhatsApp Business Account configured"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Template or sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders": {
      "get": {
        "summary": "List senders",
        "operationId": "listSenders",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of sender profiles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Sender"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create sender",
        "operationId": "createSender",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SenderCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sender created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sender"
                }
              }
            }
          },
          "400": {
            "description": "Invalid sender.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}": {
      "get": {
        "summary": "Get sender",
        "operationId": "getSender",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Sender details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sender"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update sender",
        "operationId": "updateSender",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SenderUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sender updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sender"
                }
              }
            }
          },
          "400": {
            "description": "Invalid update.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete sender",
        "operationId": "deleteSender",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Sender deleted."
          },
          "400": {
            "description": "Cannot delete default sender.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/webhook/secret": {
      "post": {
        "summary": "Regenerate webhook secret",
        "description": "Regenerate the webhook secret for a sender. The old secret will be invalidated immediately.",
        "operationId": "regenerateSenderWebhookSecret",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "New webhook secret generated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecretResponse"
                }
              }
            }
          },
          "400": {
            "description": "Sender has no webhook configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/profile": {
      "get": {
        "summary": "Get WhatsApp Business profile",
        "description": "Get the WhatsApp Business profile for a sender. The sender must have a WhatsApp Business Account connected.",
        "operationId": "getSenderProfile",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "WhatsApp Business profile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhatsAppBusinessProfileResponse"
                }
              }
            }
          },
          "400": {
            "description": "Sender does not have a WhatsApp Business Account connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update WhatsApp Business profile",
        "description": "Update the WhatsApp Business profile for a sender. The sender must have a WhatsApp Business Account connected.",
        "operationId": "updateSenderProfile",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsAppBusinessProfileUpdateRequest"
              },
              "example": {
                "about": "Succulent specialists!",
                "description": "We specialize in providing high-quality succulents.",
                "email": "contact@example.com",
                "websites": [
                  "https://www.example.com"
                ],
                "vertical": "RETAIL"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "profile"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "profile": {
                      "$ref": "#/components/schemas/WhatsAppBusinessProfile"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or sender does not have a WhatsApp Business Account connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/profile/picture": {
      "post": {
        "summary": "Upload WhatsApp Business profile picture",
        "description": "Upload a new profile picture for the WhatsApp Business profile. The image will be uploaded to Meta and set as the profile picture.",
        "operationId": "uploadSenderProfilePicture",
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsAppBusinessProfilePictureRequest"
              },
              "example": {
                "imageUrl": "https://example.com/profile.jpg",
                "mimeType": "image/jpeg"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile picture uploaded successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "profile"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "profile": {
                      "$ref": "#/components/schemas/WhatsAppBusinessProfile"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or sender does not have a WhatsApp Business Account connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/whatsapp-sync": {
      "get": {
        "summary": "Get WhatsApp sync status",
        "description": "Get the current sync status for a sender's WhatsApp coexistence account. Only available for senders connected in coexistence mode (WhatsApp Business App + Cloud API).",
        "operationId": "getWhatsAppSyncStatus",
        "tags": [
          "WhatsApp Sync"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Sync status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhatsAppSyncStatusResponse"
                },
                "example": {
                  "sync": {
                    "isCoexistence": true,
                    "status": "active",
                    "history": {
                      "status": "completed",
                      "canSync": false,
                      "requestedAt": "2024-01-15T10:00:00Z",
                      "completedAt": "2024-01-15T10:05:00Z"
                    },
                    "contacts": {
                      "status": "not_requested",
                      "canSync": true,
                      "requestedAt": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Sender does not have a WhatsApp Business Account connected or is not in coexistence mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "no_waba": {
                    "summary": "No WABA connected",
                    "value": {
                      "code": "bad_request",
                      "message": "Sender does not have a WhatsApp Business Account connected"
                    }
                  },
                  "not_coexistence": {
                    "summary": "Not coexistence mode",
                    "value": {
                      "code": "bad_request",
                      "message": "Sync is only available for coexistence accounts"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/whatsapp-sync/history": {
      "post": {
        "summary": "Start history sync",
        "description": "Initiate message history sync from the WhatsApp Business App. This sends a request to the account owner to approve sharing their conversation history. Only available for coexistence accounts with active status.",
        "operationId": "startWhatsAppHistorySync",
        "tags": [
          "WhatsApp Sync"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "202": {
            "description": "History sync initiated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhatsAppSyncStartResponse"
                },
                "example": {
                  "message": "History sync initiated",
                  "sync": {
                    "isCoexistence": true,
                    "status": "active",
                    "history": {
                      "status": "pending",
                      "canSync": false,
                      "requestedAt": "2024-01-15T10:00:00Z",
                      "completedAt": null
                    },
                    "contacts": {
                      "status": "not_requested",
                      "canSync": true,
                      "requestedAt": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "no_waba": {
                    "summary": "No WABA connected",
                    "value": {
                      "code": "bad_request",
                      "message": "Sender does not have a WhatsApp Business Account connected"
                    }
                  },
                  "not_coexistence": {
                    "summary": "Not coexistence mode",
                    "value": {
                      "code": "bad_request",
                      "message": "History sync is only available for coexistence accounts"
                    }
                  },
                  "not_active": {
                    "summary": "Account not active",
                    "value": {
                      "code": "bad_request",
                      "message": "WhatsApp account is not active"
                    }
                  },
                  "in_progress": {
                    "summary": "Sync in progress",
                    "value": {
                      "code": "bad_request",
                      "message": "History sync is already in progress"
                    }
                  },
                  "rate_limit": {
                    "summary": "Rate limit",
                    "value": {
                      "code": "bad_request",
                      "message": "Sync limit reached. Please wait 24 hours before trying again."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/whatsapp-sync/contacts": {
      "post": {
        "summary": "Start contacts sync",
        "description": "Initiate contact names sync from the WhatsApp Business App. This imports contact names stored in the app to Zavu. Only available for coexistence accounts with active status.",
        "operationId": "startWhatsAppContactsSync",
        "tags": [
          "WhatsApp Sync"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "202": {
            "description": "Contacts sync initiated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhatsAppSyncStartResponse"
                },
                "example": {
                  "message": "Contacts sync initiated",
                  "sync": {
                    "isCoexistence": true,
                    "status": "active",
                    "history": {
                      "status": "completed",
                      "canSync": false,
                      "requestedAt": "2024-01-15T10:00:00Z",
                      "completedAt": "2024-01-15T10:05:00Z"
                    },
                    "contacts": {
                      "status": "pending",
                      "canSync": false,
                      "requestedAt": "2024-01-15T11:00:00Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "no_waba": {
                    "summary": "No WABA connected",
                    "value": {
                      "code": "bad_request",
                      "message": "Sender does not have a WhatsApp Business Account connected"
                    }
                  },
                  "not_coexistence": {
                    "summary": "Not coexistence mode",
                    "value": {
                      "code": "bad_request",
                      "message": "Contacts sync is only available for coexistence accounts"
                    }
                  },
                  "not_active": {
                    "summary": "Account not active",
                    "value": {
                      "code": "bad_request",
                      "message": "WhatsApp account is not active"
                    }
                  },
                  "in_progress": {
                    "summary": "Sync in progress",
                    "value": {
                      "code": "bad_request",
                      "message": "Contacts sync is already in progress"
                    }
                  },
                  "rate_limit": {
                    "summary": "Rate limit",
                    "value": {
                      "code": "bad_request",
                      "message": "Sync limit reached. Please wait 24 hours before trying again."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts": {
      "get": {
        "summary": "List contacts",
        "description": "List contacts with their communication channels.",
        "operationId": "listContacts",
        "parameters": [
          {
            "name": "phoneNumber",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of contacts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contact"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create contact",
        "description": "Create a new contact with one or more communication channels.",
        "operationId": "createContact",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactCreateRequest"
              },
              "examples": {
                "phone_only": {
                  "summary": "Contact with phone only",
                  "value": {
                    "displayName": "John Doe",
                    "channels": [
                      {
                        "channel": "sms",
                        "identifier": "+14155551234",
                        "isPrimary": true
                      }
                    ]
                  }
                },
                "multi_channel": {
                  "summary": "Contact with multiple channels",
                  "value": {
                    "displayName": "John Doe",
                    "channels": [
                      {
                        "channel": "sms",
                        "identifier": "+14155551234",
                        "isPrimary": true
                      },
                      {
                        "channel": "whatsapp",
                        "identifier": "+14155551234",
                        "isPrimary": true
                      },
                      {
                        "channel": "email",
                        "identifier": "john@example.com",
                        "isPrimary": true
                      }
                    ],
                    "metadata": {
                      "source": "import"
                    }
                  }
                },
                "email_only": {
                  "summary": "Contact with email only",
                  "value": {
                    "displayName": "Jane Smith",
                    "channels": [
                      {
                        "channel": "email",
                        "identifier": "jane@example.com",
                        "isPrimary": true
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Contact created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "duplicate_identifier": {
                    "summary": "Duplicate identifier",
                    "value": {
                      "code": "bad_request",
                      "message": "This sms identifier is already associated with another contact"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/{contactId}": {
      "get": {
        "summary": "Get contact",
        "operationId": "getContact",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Contact details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update contact",
        "operationId": "updateContact",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "Invalid update.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete contact",
        "description": "Permanently delete a contact and its communication channels. Implements right-to-erasure obligations under GDPR Art. 17, Ley 19.628 (Chile) Art. 12, CCPA § 1798.105, and LGPD Art. 18.VI. The contact, its channels, and any associated agent flow sessions and conversation threads are removed. Past message records and broadcast delivery logs are retained for billing/audit but no longer reference the deleted contact.",
        "operationId": "deleteContact",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Contact deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/phone/{phoneNumber}": {
      "get": {
        "summary": "Get contact by phone number",
        "operationId": "getContactByPhone",
        "parameters": [
          {
            "name": "phoneNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "E.164 phone number."
          }
        ],
        "responses": {
          "200": {
            "description": "Contact details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/{contactId}/channels": {
      "post": {
        "summary": "Add channel to contact",
        "description": "Add a new communication channel to an existing contact.",
        "operationId": "addContactChannel",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddChannelRequest"
              },
              "example": {
                "channel": "email",
                "identifier": "john.work@company.com",
                "label": "work"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Channel added.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactChannelResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or duplicate identifier.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/{contactId}/channels/{channelId}": {
      "patch": {
        "summary": "Update channel",
        "description": "Update a contact's channel properties.",
        "operationId": "updateContactChannel",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          },
          {
            "name": "channelId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel ID."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateChannelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Channel updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactChannelResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact or channel not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Remove channel from contact",
        "description": "Remove a communication channel from a contact. Cannot remove the last channel.",
        "operationId": "removeContactChannel",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          },
          {
            "name": "channelId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel ID."
          }
        ],
        "responses": {
          "204": {
            "description": "Channel removed."
          },
          "400": {
            "description": "Cannot remove the last channel.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact or channel not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/{contactId}/channels/{channelId}/primary": {
      "post": {
        "summary": "Set channel as primary",
        "description": "Set a channel as the primary channel for its type.",
        "operationId": "setPrimaryChannel",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          },
          {
            "name": "channelId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Channel set as primary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactChannelResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact or channel not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/{contactId}/merge": {
      "post": {
        "summary": "Merge contacts",
        "description": "Merge a source contact into this contact. All channels from the source contact will be moved to the target contact, and the source contact will be marked as merged.",
        "operationId": "mergeContacts",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MergeContactsRequest"
              },
              "example": {
                "sourceContactId": "jx7xyz789"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contacts merged. Returns the updated target contact.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g., cannot merge contact with itself).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Target or source contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/contacts/{contactId}/merge-suggestion": {
      "delete": {
        "summary": "Dismiss merge suggestion",
        "description": "Dismiss the merge suggestion for a contact.",
        "operationId": "dismissMergeSuggestion",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Merge suggestion dismissed."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/conversations": {
      "get": {
        "summary": "List conversations",
        "description": "List inbox threads, most recently active first. A conversation groups every message with one contact across channels, which is what you need to build an inbox: `GET /v1/messages` returns a flat log with no thread to hang it on.\n\nUse `senderId` to scope the list to a single number, and `channel` to keep only threads that have carried that channel.",
        "operationId": "listConversations",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "description": "Keep only threads that have carried this channel.",
            "schema": {
              "type": "string",
              "enum": [
                "sms",
                "sms_oneway",
                "whatsapp",
                "email",
                "telegram",
                "instagram",
                "messenger",
                "voice"
              ]
            }
          },
          {
            "name": "senderId",
            "in": "query",
            "description": "Keep only threads last handled by this sender.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque cursor from a previous response's `nextCursor`. Do not construct it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of conversations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Conversation"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/conversations/{conversationId}": {
      "get": {
        "summary": "Get conversation",
        "operationId": "getConversation",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConversationIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Conversation details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Conversation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/conversations/{conversationId}/messages": {
      "get": {
        "summary": "List conversation messages",
        "description": "Messages in this thread, newest first, across every channel it has carried. Reply with `POST /v1/messages`, passing the conversation's `senderId` as the `Zavu-Sender` header so the answer leaves from the number the contact already knows.",
        "operationId": "listConversationMessages",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConversationIdParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque cursor from a previous response's `nextCursor`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of messages.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Message"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Conversation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/conversations/{conversationId}/read": {
      "post": {
        "summary": "Mark conversation as read",
        "description": "Reset the thread's `unreadCount` to zero. Marks the thread read in your own inbox only: it does not send a read receipt to the contact.",
        "operationId": "markConversationRead",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConversationIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Conversation marked as read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Conversation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/introspect/phone": {
      "post": {
        "summary": "Introspect phone number",
        "description": "Validate a phone number and check if a WhatsApp conversation window is open.",
        "operationId": "introspectPhone",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhoneIntrospectionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Phone number introspection result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneIntrospectionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid phone number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/introspect/email": {
      "post": {
        "summary": "Validate email addresses",
        "description": "Heuristic email validation to run before sending: catches invalid syntax, dead domains (no MX/A records), disposable inboxes, role-based addresses (info@, contacto@, sales@), and addresses already on your project's suppression list. Use it to clean a list before a broadcast and keep your bounce rate low.\n\nNo mailbox-level (SMTP) probe is performed, so a `deliverable` verdict is not a delivery guarantee — it means no negative signal was found. Treat `risky` addresses with care and drop `undeliverable` ones.\n\nAccepts a single `email` or an `emails` batch (max 100 per request).",
        "operationId": "introspectEmail",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailIntrospectionRequest"
              },
              "examples": {
                "single": {
                  "summary": "Validate one address",
                  "value": {
                    "email": "maria@example.com"
                  }
                },
                "batch": {
                  "summary": "Validate a list",
                  "value": {
                    "emails": [
                      "maria@example.com",
                      "info@deaddomain.example",
                      "not-an-email"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation results, one per submitted address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailIntrospectionResponse"
                },
                "example": {
                  "results": [
                    {
                      "email": "maria@example.com",
                      "normalized": "maria@example.com",
                      "domain": "example.com",
                      "verdict": "deliverable",
                      "reasons": []
                    },
                    {
                      "email": "info@deaddomain.example",
                      "normalized": "info@deaddomain.example",
                      "domain": "deaddomain.example",
                      "verdict": "undeliverable",
                      "reasons": [
                        "domain_not_found",
                        "role_address"
                      ]
                    },
                    {
                      "email": "not-an-email",
                      "normalized": null,
                      "domain": null,
                      "verdict": "undeliverable",
                      "reasons": [
                        "invalid_syntax"
                      ]
                    }
                  ],
                  "summary": {
                    "total": 3,
                    "deliverable": 1,
                    "risky": 0,
                    "undeliverable": 2
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body (no addresses, or more than 100).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts": {
      "post": {
        "summary": "Create broadcast",
        "description": "Create a new broadcast campaign. Add contacts after creation, then send.",
        "operationId": "createBroadcast",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastCreateRequest"
              },
              "examples": {
                "sms": {
                  "summary": "SMS broadcast",
                  "value": {
                    "name": "Black Friday Sale",
                    "channel": "sms",
                    "text": "Hi {{name}}, check out our Black Friday deals! Use code FRIDAY20 for 20% off."
                  }
                },
                "whatsapp_template": {
                  "summary": "WhatsApp template broadcast",
                  "value": {
                    "name": "Order Confirmation Campaign",
                    "channel": "whatsapp",
                    "messageType": "template",
                    "content": {
                      "templateId": "tmpl_abc123"
                    }
                  }
                },
                "telegram": {
                  "summary": "Telegram broadcast",
                  "value": {
                    "name": "Product Announcement",
                    "channel": "telegram",
                    "text": "Hi {{name}}, check out our new product launch!"
                  }
                },
                "email": {
                  "summary": "Email broadcast",
                  "value": {
                    "name": "Newsletter",
                    "channel": "email",
                    "emailSubject": "Your Weekly Update",
                    "text": "Hi {{name}}, here's what's new this week..."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Broadcast created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict (broadcast already exists).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List broadcasts",
        "description": "List broadcasts for this project.",
        "operationId": "listBroadcasts",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/BroadcastStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of broadcasts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Broadcast"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}": {
      "get": {
        "summary": "Get broadcast",
        "operationId": "getBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Broadcast details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update broadcast",
        "description": "Update a broadcast in draft status.",
        "operationId": "updateBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Broadcast updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or broadcast not in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete broadcast",
        "description": "Delete a broadcast in draft status.",
        "operationId": "deleteBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Broadcast deleted."
          },
          "400": {
            "description": "Broadcast not in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/contacts": {
      "post": {
        "summary": "Add contacts to broadcast",
        "description": "Add contacts to a broadcast in batch. Maximum 1000 contacts per request.",
        "operationId": "addBroadcastContacts",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastContactsAddRequest"
              },
              "example": {
                "contacts": [
                  {
                    "recipient": "+14155551234",
                    "templateVariables": {
                      "name": "John",
                      "order_id": "ORD-001"
                    }
                  },
                  {
                    "recipient": "+14155555678",
                    "templateVariables": {
                      "name": "Jane",
                      "order_id": "ORD-002"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Contacts added.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastContactsAddResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or broadcast not in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List broadcast contacts",
        "description": "List contacts in a broadcast with optional status filter.",
        "operationId": "listBroadcastContacts",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/BroadcastContactStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of broadcast contacts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BroadcastContact"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/contacts/{contactId}": {
      "delete": {
        "summary": "Remove contact from broadcast",
        "description": "Remove a contact from a broadcast in draft status.",
        "operationId": "removeBroadcastContact",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          },
          {
            "$ref": "#/components/parameters/BroadcastContactIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Contact removed."
          },
          "400": {
            "description": "Broadcast not in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast or contact not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/send": {
      "post": {
        "summary": "Send broadcast",
        "description": "Start sending the broadcast immediately or schedule for later.\n\n**Verification is required to send, and there are two of them.** The team must have completed both identity verification (KYC) and business verification (KYB); passing one is not enough. Drafts can be created, edited and kept without either. Every send path — dashboard, API and CLI alike — enforces both, returning `403` with code `kyc_required` or `kyb_required` for whichever is outstanding.\n\n**Review depends on the channel, and cannot be bypassed.** A draft is submitted to automated content review here; it does not go straight out. A WhatsApp broadcast built on a Meta-approved template skips review (Meta already vetted the content) and begins sending. An email broadcast sends as soon as the automated review passes. Every other channel moves to `pending_admin_review` and waits for a person. If the review rejects it, use PATCH to edit the content then call POST /retry-review.\n\nCalling this on a broadcast that is already `approved` or `scheduled` sends or reschedules it directly, since it has already been reviewed. Reserves the estimated cost from your balance.",
        "operationId": "sendBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastSendRequest"
              },
              "examples": {
                "immediate": {
                  "summary": "Send immediately",
                  "value": {}
                },
                "scheduled": {
                  "summary": "Schedule for later",
                  "value": {
                    "scheduledAt": "2024-01-15T10:00:00Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Broadcast started or scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, no contacts, or broadcast not in valid status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "insufficient_balance",
                  "message": "Insufficient balance. Available: $50.00",
                  "details": {
                    "totalBalance": 50,
                    "reservedBalance": 25,
                    "availableBalance": 25
                  }
                }
              }
            }
          },
          "403": {
            "description": "Verification required. Sending needs both identity (KYC) and business (KYB) verification; the code says which one is missing. Drafts are unaffected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "kyc_required": {
                    "summary": "Identity not verified",
                    "value": {
                      "code": "kyc_required",
                      "message": "Verify your identity before sending broadcasts. Drafts can be created and edited without it.",
                      "details": {
                        "dashboardUrl": "/kyc"
                      }
                    }
                  },
                  "kyb_required": {
                    "summary": "Business not verified",
                    "value": {
                      "code": "kyb_required",
                      "message": "Complete Business Verification before sending broadcasts. Drafts can be created and edited without it.",
                      "details": {
                        "dashboardUrl": "/compliance/verify"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/schedule": {
      "patch": {
        "summary": "Reschedule broadcast",
        "description": "Update the scheduled time for a broadcast. The broadcast must be in scheduled status.",
        "operationId": "rescheduleBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastRescheduleRequest"
              },
              "example": {
                "scheduledAt": "2024-01-15T14:00:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Broadcast rescheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or broadcast not in scheduled status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/cancel": {
      "post": {
        "summary": "Cancel broadcast",
        "description": "Cancel a broadcast. Pending contacts will be skipped, but already queued messages may still be delivered.",
        "operationId": "cancelBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Broadcast cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Broadcast cannot be cancelled in current status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/retry-review": {
      "post": {
        "summary": "Retry broadcast review",
        "description": "Resubmit a rejected broadcast for AI review after editing content. Maximum 3 review attempts allowed per broadcast.",
        "operationId": "retryBroadcastReview",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Review resubmitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Broadcast not in rejected status or max attempts reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "not_rejected": {
                    "summary": "Broadcast not rejected",
                    "value": {
                      "code": "invalid_request",
                      "message": "Only rejected broadcasts can retry review"
                    }
                  },
                  "max_attempts": {
                    "summary": "Max attempts reached",
                    "value": {
                      "code": "invalid_request",
                      "message": "Maximum review attempts reached. Request manual review instead."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/escalate": {
      "post": {
        "summary": "Escalate to manual review",
        "description": "Request manual review by the Zavu team for a rejected broadcast. Use this after automated review rejection if you believe the content is legitimate.",
        "operationId": "escalateBroadcast",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Escalation submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastResponse"
                }
              }
            }
          },
          "400": {
            "description": "Broadcast not in rejected status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_request",
                  "message": "Only rejected broadcasts can be escalated"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/broadcasts/{broadcastId}/progress": {
      "get": {
        "summary": "Get broadcast progress",
        "description": "Get real-time progress of a broadcast including delivery counts and estimated completion time.",
        "operationId": "getBroadcastProgress",
        "parameters": [
          {
            "$ref": "#/components/parameters/BroadcastIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Broadcast progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastProgress"
                },
                "example": {
                  "broadcastId": "brd_abc123",
                  "status": "sending",
                  "total": 5000,
                  "pending": 2500,
                  "sending": 100,
                  "delivered": 2350,
                  "failed": 50,
                  "skipped": 0,
                  "percentComplete": 48,
                  "estimatedCost": 75,
                  "reservedAmount": 75,
                  "actualCost": 35.25,
                  "startedAt": "2024-01-15T10:30:00.000Z",
                  "estimatedCompletionAt": "2024-01-15T10:45:00.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Broadcast not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/phone-numbers/requirements": {
      "get": {
        "summary": "Get regulatory requirements",
        "description": "Get regulatory requirements for purchasing phone numbers in a specific country. Some countries require additional documentation (addresses, identity documents) before phone numbers can be activated.",
        "operationId": "getPhoneNumberRequirements",
        "parameters": [
          {
            "name": "countryCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "example": "DE",
            "description": "Two-letter ISO country code."
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PhoneNumberType"
            },
            "description": "Type of phone number (local, mobile, tollFree)."
          }
        ],
        "responses": {
          "200": {
            "description": "List of requirements for the country/type combination.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Requirement"
                      }
                    }
                  }
                },
                "example": {
                  "items": [
                    {
                      "id": "req_123",
                      "countryCode": "DE",
                      "phoneNumberType": "local",
                      "action": "ordering",
                      "requirementTypes": [
                        {
                          "id": "address_proof",
                          "name": "Proof of Address",
                          "description": "A document proving your address in Germany",
                          "type": "document"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/phone-numbers/available": {
      "get": {
        "summary": "Search available phone numbers",
        "description": "Search for available phone numbers to purchase by country and type.",
        "operationId": "searchAvailablePhoneNumbers",
        "parameters": [
          {
            "name": "countryCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            },
            "example": "US",
            "description": "Two-letter ISO country code."
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PhoneNumberType"
            },
            "description": "Type of phone number to search for."
          },
          {
            "name": "contains",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "description": "Search for numbers containing this string."
          },
          {
            "name": "capabilities",
            "in": "query",
            "description": "Comma-separated capabilities the number must have: `sms`, `voice`, `mms`. Numbers missing any of them are dropped.",
            "schema": {
              "type": "string",
              "example": "voice,sms"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "maximum": 50
            },
            "description": "Maximum number of results to return."
          }
        ],
        "responses": {
          "200": {
            "description": "List of available phone numbers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AvailablePhoneNumber"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/phone-numbers": {
      "post": {
        "summary": "Purchase a phone number",
        "description": "Purchase an available phone number. Requires a paid plan: the Free plan cannot purchase phone numbers and receives `402` with code `paid_plan_required`. Paid plans include the first US number at no charge.",
        "operationId": "purchasePhoneNumber",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhoneNumberPurchaseRequest"
              },
              "example": {
                "phoneNumber": "+15551234567",
                "name": "Primary Line"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Phone number purchased successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or phone number no longer available.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. Either the balance cannot cover the purchase (code `insufficient_balance`) or the team is on the Free plan (code `paid_plan_required`): buying phone numbers requires a paid plan, which includes the first US number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "insufficient_balance": {
                    "summary": "Balance cannot cover the purchase",
                    "value": {
                      "code": "insufficient_balance",
                      "message": "Insufficient balance. Required: $1.25. Please add funds to continue."
                    }
                  },
                  "paid_plan_required": {
                    "summary": "Free plan cannot purchase numbers",
                    "value": {
                      "code": "paid_plan_required",
                      "message": "Buying phone numbers requires a paid plan. Upgrade to Pro to get one US number included."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List phone numbers",
        "description": "List all phone numbers owned by this project.",
        "operationId": "listPhoneNumbers",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PhoneNumberStatus"
            },
            "description": "Filter by phone number status."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Pagination cursor."
          }
        ],
        "responses": {
          "200": {
            "description": "List of phone numbers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OwnedPhoneNumber"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/phone-numbers/{phoneNumberId}": {
      "get": {
        "summary": "Get phone number",
        "description": "Get details of a specific phone number.",
        "operationId": "getPhoneNumber",
        "parameters": [
          {
            "$ref": "#/components/parameters/PhoneNumberIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Phone number details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Phone number not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update phone number",
        "description": "Update a phone number's name or sender assignment.",
        "operationId": "updatePhoneNumber",
        "parameters": [
          {
            "$ref": "#/components/parameters/PhoneNumberIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhoneNumberUpdateRequest"
              },
              "examples": {
                "rename": {
                  "summary": "Rename phone number",
                  "value": {
                    "name": "Support Line"
                  }
                },
                "assign": {
                  "summary": "Assign to sender",
                  "value": {
                    "senderId": "sender_abc123"
                  }
                },
                "unassign": {
                  "summary": "Unassign from sender",
                  "value": {
                    "senderId": null
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Phone number updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhoneNumberResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Phone number or sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Release phone number",
        "description": "Release a phone number. The phone number must not be assigned to a sender.",
        "operationId": "releasePhoneNumber",
        "parameters": [
          {
            "$ref": "#/components/parameters/PhoneNumberIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Phone number released."
          },
          "400": {
            "description": "Cannot release phone number assigned to a sender.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Phone number not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/invitations": {
      "post": {
        "summary": "Create invitation",
        "description": "Create a partner invitation link for a client to connect a Meta channel. The client opens the returned `url` and authorizes with Meta; the resulting sender is created in your project when they finish, and the invitation transitions to `completed`.\n\n`connectionType` picks the channel:\n- `whatsapp_waba` (default): Meta's embedded signup links an official WhatsApp Business Account.\n- `messenger`: the client picks a Facebook Page they administer; its Messenger inbox (including Marketplace chats) is routed to Zavu.\n\nOne invitation connects one channel — create one per channel to onboard a client on several. `phoneNumberId` and `allowedPhoneCountries` apply to `whatsapp_waba` only.",
        "operationId": "createInvitation",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvitationCreateRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic invitation",
                  "value": {
                    "clientName": "Acme Corp"
                  }
                },
                "full": {
                  "summary": "Full invitation with all options",
                  "value": {
                    "clientName": "Acme Corp",
                    "clientEmail": "contact@acme.com",
                    "clientPhone": "+14155551234",
                    "expiresInDays": 14,
                    "allowedPhoneCountries": [
                      "US",
                      "MX"
                    ]
                  }
                },
                "messenger": {
                  "summary": "Messenger invitation (Facebook Page)",
                  "value": {
                    "clientName": "Acme Corp",
                    "clientEmail": "contact@acme.com",
                    "connectionType": "messenger"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invitation created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List invitations",
        "description": "List partner invitations for this project.",
        "operationId": "listInvitations",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/InvitationStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of invitations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Invitation"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/invitations/{invitationId}": {
      "get": {
        "summary": "Get invitation",
        "operationId": "getInvitation",
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Invitation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/invitations/{invitationId}/cancel": {
      "post": {
        "summary": "Cancel invitation",
        "description": "Cancel an active invitation. The client will no longer be able to use the invitation link.",
        "operationId": "cancelInvitation",
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Cannot cancel this invitation (already completed or cancelled).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Invitation not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/addresses": {
      "post": {
        "summary": "Create address",
        "description": "Create a regulatory address for phone number purchases. Some countries require a verified address before phone numbers can be activated.",
        "operationId": "createAddress",
        "tags": [
          "Regulatory"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddressCreateRequest"
              },
              "example": {
                "firstName": "John",
                "lastName": "Doe",
                "streetAddress": "123 Main St",
                "locality": "Berlin",
                "postalCode": "10115",
                "countryCode": "DE"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Address created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List addresses",
        "description": "List regulatory addresses for this project.",
        "operationId": "listAddresses",
        "tags": [
          "Regulatory"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of addresses.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Address"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/addresses/{addressId}": {
      "get": {
        "summary": "Get address",
        "description": "Get a specific regulatory address.",
        "operationId": "getAddress",
        "tags": [
          "Regulatory"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AddressIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Address details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Address not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete address",
        "description": "Delete a regulatory address. Cannot delete addresses that are in use.",
        "operationId": "deleteAddress",
        "tags": [
          "Regulatory"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AddressIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Address deleted."
          },
          "400": {
            "description": "Cannot delete address that is in use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Address not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/documents": {
      "post": {
        "summary": "Create document",
        "description": "Create a regulatory document record after uploading the file. Use the upload-url endpoint first to get an upload URL.",
        "operationId": "createRegulatoryDocument",
        "tags": [
          "Regulatory"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegulatoryDocumentCreateRequest"
              },
              "example": {
                "name": "Passport Scan",
                "documentType": "passport",
                "storageId": "kg2abc123...",
                "mimeType": "image/jpeg",
                "fileSize": 102400
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Document created and uploaded to verification provider.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryDocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or upload failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List documents",
        "description": "List regulatory documents for this project.",
        "operationId": "listRegulatoryDocuments",
        "tags": [
          "Regulatory"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RegulatoryDocument"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/documents/upload-url": {
      "post": {
        "summary": "Get document upload URL",
        "description": "Get a presigned URL to upload a document file. After uploading, use the storageId to create the document record.",
        "operationId": "getRegulatoryDocumentUploadUrl",
        "tags": [
          "Regulatory"
        ],
        "responses": {
          "200": {
            "description": "Upload URL generated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadUrlResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/documents/{documentId}": {
      "get": {
        "summary": "Get document",
        "description": "Get a specific regulatory document.",
        "operationId": "getRegulatoryDocument",
        "tags": [
          "Regulatory"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RegulatoryDocumentIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Document details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegulatoryDocumentResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Document not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete document",
        "description": "Delete a regulatory document. Cannot delete verified documents.",
        "operationId": "deleteRegulatoryDocument",
        "tags": [
          "Regulatory"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RegulatoryDocumentIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Document deleted."
          },
          "400": {
            "description": "Cannot delete a verified document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Document not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent": {
      "get": {
        "summary": "Get agent",
        "description": "Get the AI agent configuration for a sender.",
        "operationId": "getAgent",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Agent configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender or agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create agent",
        "description": "Create an AI agent for a sender. Each sender can have at most one agent.",
        "operationId": "createAgent",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentCreateRequest"
              },
              "example": {
                "name": "Customer Support",
                "provider": "openai",
                "model": "gpt-4o-mini",
                "systemPrompt": "You are a helpful customer support agent. Be friendly and concise.",
                "apiKey": "sk-..."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Agent created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or agent already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update agent",
        "description": "Update an AI agent's configuration.",
        "operationId": "updateAgent",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Agent updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender or agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete agent",
        "description": "Delete an AI agent.",
        "operationId": "deleteAgent",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Agent deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender or agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/stats": {
      "get": {
        "summary": "Get agent statistics",
        "description": "Get statistics for an AI agent including invocations, tokens, and costs.\n\nCovers the messaging channels only. Voice calls are not counted here: a call is a multi-turn conversation rather than one inbound message and one reply, so it is recorded as a call, not an execution. An agent that only answers phone calls reports zeros on every field. Use `GET /v1/calls` for voice activity, duration, and cost.",
        "operationId": "getAgentStats",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Agent statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentStats"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/executions": {
      "get": {
        "summary": "List agent executions",
        "description": "List recent agent executions with pagination.\n\nAn execution is one inbound message answered by the agent, so this covers the messaging channels only. Voice calls are never listed here regardless of how many the agent handled. Use `GET /v1/calls` (and `GET /v1/calls/{callId}` for the transcript) for voice.",
        "operationId": "listAgentExecutions",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/AgentExecutionStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of executions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentExecution"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/executions/{executionId}": {
      "get": {
        "summary": "Get a single agent execution",
        "description": "Fetch full details for one execution — including `errorMessage`, `errorCode`, and `responseText`. Use this to debug failures surfaced by the list endpoint.",
        "operationId": "getAgentExecution",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "name": "executionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Execution details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "execution"
                  ],
                  "properties": {
                    "execution": {
                      "$ref": "#/components/schemas/AgentExecution"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent or execution not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/flows": {
      "get": {
        "summary": "List flows",
        "description": "List flows for an agent.",
        "operationId": "listAgentFlows",
        "tags": [
          "Agent Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "name": "enabled",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of flows.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentFlow"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create flow",
        "description": "Create a new flow for an agent.",
        "operationId": "createAgentFlow",
        "tags": [
          "Agent Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FlowCreateRequest"
              },
              "example": {
                "name": "Lead Capture",
                "description": "Capture lead information",
                "trigger": {
                  "type": "keyword",
                  "keywords": [
                    "info",
                    "pricing",
                    "demo"
                  ]
                },
                "steps": [
                  {
                    "id": "welcome",
                    "type": "message",
                    "config": {
                      "text": "Thanks for your interest! Let me get some info."
                    },
                    "nextStepId": "ask_name"
                  },
                  {
                    "id": "ask_name",
                    "type": "collect",
                    "config": {
                      "variable": "name",
                      "prompt": "What's your name?"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Flow created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlowResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/flows/{flowId}": {
      "get": {
        "summary": "Get flow",
        "description": "Get a specific flow.",
        "operationId": "getAgentFlow",
        "tags": [
          "Agent Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/FlowIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Flow details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlowResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Flow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update flow",
        "description": "Update a flow.",
        "operationId": "updateAgentFlow",
        "tags": [
          "Agent Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/FlowIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FlowUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Flow updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlowResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Flow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete flow",
        "description": "Delete a flow. Cannot delete flows with active sessions.",
        "operationId": "deleteAgentFlow",
        "tags": [
          "Agent Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/FlowIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Flow deleted."
          },
          "400": {
            "description": "Cannot delete flow with active sessions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Flow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/flows/{flowId}/duplicate": {
      "post": {
        "summary": "Duplicate flow",
        "description": "Create a copy of an existing flow with a new name.",
        "operationId": "duplicateAgentFlow",
        "tags": [
          "Agent Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/FlowIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FlowDuplicateRequest"
              },
              "example": {
                "newName": "Lead Capture (Copy)"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Flow duplicated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlowResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Flow not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/tools": {
      "get": {
        "summary": "List tools",
        "description": "List tools for an agent.",
        "operationId": "listAgentTools",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "name": "enabled",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of tools.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentTool"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create tool",
        "description": "Create a new tool for an agent. Tools allow the agent to call external webhooks.",
        "operationId": "createAgentTool",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolCreateRequest"
              },
              "example": {
                "name": "get_order_status",
                "description": "Get the status of a customer order",
                "webhookUrl": "https://api.example.com/webhooks/order-status",
                "webhookSecret": "whsec_...",
                "parameters": {
                  "type": "object",
                  "properties": {
                    "order_id": {
                      "type": "string",
                      "description": "The order ID to look up"
                    }
                  },
                  "required": [
                    "order_id"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Tool created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/tools/{toolId}": {
      "get": {
        "summary": "Get tool",
        "description": "Get a specific tool.",
        "operationId": "getAgentTool",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/ToolIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Tool details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update tool",
        "description": "Update a tool.",
        "operationId": "updateAgentTool",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/ToolIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tool updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete tool",
        "description": "Delete a tool.",
        "operationId": "deleteAgentTool",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/ToolIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Tool deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/tools/{toolId}/test": {
      "post": {
        "summary": "Test tool",
        "description": "Run a tool with the parameters you supply and return what it answered.\n\nThe call is synchronous: the response carries the tool's status, body, and duration, so a green result is evidence the tool ran rather than evidence it was accepted. Each run is also recorded and readable afterwards via `GET /v1/senders/{senderId}/agent/tools/{toolId}/test-runs`.\n\nA tool that answers with an error is reported as a run with `success: false` — the endpoint itself still returns 200. This fires the tool's real webhook, so a test has whatever side effects the tool has.",
        "operationId": "testAgentTool",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/ToolIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ToolTestRequest"
              },
              "example": {
                "testParams": {
                  "order_id": "ORD-12345"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool ran. Check `run.success` for what it answered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolTestResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/tools/{toolId}/test-runs": {
      "get": {
        "summary": "List tool test runs",
        "description": "Recent runs of this tool triggered from the test endpoint, newest first. Covers manual tests only: a tool called by an agent during a real conversation is not recorded here.",
        "operationId": "listAgentToolTestRuns",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/ToolIdParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recent test runs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentToolTestRun"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/knowledge-bases": {
      "get": {
        "summary": "List knowledge bases",
        "description": "List knowledge bases for an agent.",
        "operationId": "listAgentKnowledgeBases",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of knowledge bases.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentKnowledgeBase"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create knowledge base",
        "description": "Create a new knowledge base for an agent.",
        "operationId": "createAgentKnowledgeBase",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KnowledgeBaseCreateRequest"
              },
              "example": {
                "name": "Product FAQ",
                "description": "Frequently asked questions about our products"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Knowledge base created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBaseResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/knowledge-bases/{kbId}": {
      "get": {
        "summary": "Get knowledge base",
        "description": "Get a specific knowledge base.",
        "operationId": "getAgentKnowledgeBase",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Knowledge base details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBaseResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Knowledge base not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update knowledge base",
        "description": "Update a knowledge base.",
        "operationId": "updateAgentKnowledgeBase",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KnowledgeBaseUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Knowledge base updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KnowledgeBaseResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Knowledge base not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete knowledge base",
        "description": "Delete a knowledge base and all its documents.",
        "operationId": "deleteAgentKnowledgeBase",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Knowledge base deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Knowledge base not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/knowledge-bases/{kbId}/documents": {
      "get": {
        "summary": "List documents",
        "description": "List documents in a knowledge base.",
        "operationId": "listAgentDocuments",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentDocument"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Knowledge base not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create document",
        "description": "Add a document to a knowledge base. The document will be automatically processed for RAG.",
        "operationId": "createAgentDocument",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentCreateRequest"
              },
              "example": {
                "title": "Return Policy",
                "content": "Our return policy allows returns within 30 days of purchase..."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Document created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Knowledge base not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/knowledge-bases/{kbId}/documents/{docId}": {
      "get": {
        "summary": "Get document",
        "description": "Get a single document from a knowledge base.",
        "operationId": "getAgentDocument",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          },
          {
            "$ref": "#/components/parameters/DocumentIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Document details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Document not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update document",
        "description": "Update a document's title or content. Updating content reprocesses the document for RAG.",
        "operationId": "updateAgentDocument",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          },
          {
            "$ref": "#/components/parameters/DocumentIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DocumentUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Document not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete document",
        "description": "Delete a document from a knowledge base.",
        "operationId": "deleteAgentDocument",
        "tags": [
          "Agent Knowledge Bases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/KnowledgeBaseIdParam"
          },
          {
            "$ref": "#/components/parameters/DocumentIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Document deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Document not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/urls": {
      "post": {
        "summary": "Submit URL for verification",
        "description": "Submit a URL for verification. URLs are automatically checked against Google Web Risk API. Safe URLs are auto-approved, malicious URLs are blocked. URL shorteners (bit.ly, t.co, etc.) are always blocked.\n\n**Important:** All SMS and Email messages containing URLs require those URLs to be verified before the message can be sent. This endpoint allows pre-verification of URLs.",
        "operationId": "submitUrl",
        "tags": [
          "URL Verification"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifiedUrlSubmitRequest"
              },
              "example": {
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "URL already verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifiedUrlResponse"
                }
              }
            }
          },
          "201": {
            "description": "URL verified and approved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifiedUrlResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "URL blocked (malicious, rejected, or shortener).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "malicious": {
                    "summary": "Malicious URL",
                    "value": {
                      "code": "url_malicious",
                      "message": "URL has been flagged as potentially harmful by security systems. This incident has been logged.",
                      "details": {
                        "urls": [
                          "https://malicious-site.com"
                        ],
                        "threatTypes": [
                          "MALWARE",
                          "SOCIAL_ENGINEERING"
                        ],
                        "warning": "fraud_prevention"
                      }
                    }
                  },
                  "shortener": {
                    "summary": "URL shortener blocked",
                    "value": {
                      "code": "url_shortener_blocked",
                      "message": "URL shorteners are not allowed. Please use the full destination URL.",
                      "details": {
                        "urls": [
                          "https://bit.ly/abc123"
                        ],
                        "reason": "url_shorteners_hidden_destination"
                      }
                    }
                  },
                  "rejected": {
                    "summary": "URL rejected",
                    "value": {
                      "code": "url_rejected",
                      "message": "URL has been rejected by our security team.",
                      "details": {
                        "urls": [
                          "https://rejected-site.com"
                        ],
                        "warning": "fraud_prevention"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List verified URLs",
        "description": "List URLs that have been verified for this project.",
        "operationId": "listUrls",
        "tags": [
          "URL Verification"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/VerifiedUrlStatus"
            },
            "description": "Filter by verification status."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of verified URLs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VerifiedUrl"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/urls/{urlId}": {
      "get": {
        "summary": "Get URL details",
        "description": "Get details of a specific verified URL.",
        "operationId": "getUrl",
        "tags": [
          "URL Verification"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/UrlIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "URL details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifiedUrlResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "URL not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/me": {
      "get": {
        "summary": "Get current API key context",
        "description": "Returns the project, team, and API key metadata bound to the current Bearer token. Used by CLIs and SDKs to confirm which project they will operate on.",
        "operationId": "getMe",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "Context for the API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "project",
                    "team",
                    "apiKey",
                    "isTestMode"
                  ],
                  "properties": {
                    "project": {
                      "type": "object",
                      "required": [
                        "id",
                        "name",
                        "isSubAccount"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string",
                          "nullable": true
                        },
                        "isSubAccount": {
                          "type": "boolean"
                        }
                      }
                    },
                    "team": {
                      "type": "object",
                      "required": [
                        "id",
                        "name"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    },
                    "apiKey": {
                      "type": "object",
                      "required": [
                        "id"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        }
                      }
                    },
                    "isTestMode": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/balance": {
      "get": {
        "summary": "Get balance",
        "description": "Get balance for the API key's team. If the API key belongs to a sub-account, also includes the sub-account's total spending and credit limit.",
        "operationId": "getBalance",
        "tags": [
          "Balance"
        ],
        "responses": {
          "200": {
            "description": "Balance details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                },
                "example": {
                  "balance": 150000,
                  "currency": "usd",
                  "creditLimit": 100000,
                  "totalSpent": 35000,
                  "isSubAccount": true
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/sub-accounts": {
      "post": {
        "summary": "Create sub-account",
        "description": "Create a new sub-account (project) with its own API key. All charges are billed to the parent team's balance. Use creditLimit to set a spending cap. The sub-account's API key is returned only in the creation response. Requires a parent project API key; sub-account API keys receive HTTP 403.",
        "operationId": "createSubAccount",
        "tags": [
          "Sub-Accounts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubAccountCreateRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic sub-account",
                  "value": {
                    "name": "Client ABC"
                  }
                },
                "with_limit": {
                  "summary": "Sub-account with spending cap",
                  "value": {
                    "name": "Client ABC",
                    "externalId": "client_123",
                    "creditLimit": 100000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sub-account created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubAccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List sub-accounts",
        "description": "List sub-accounts for this team. Requires a parent project API key; sub-account API keys receive HTTP 403.",
        "operationId": "listSubAccounts",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SubAccount"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/sub-accounts/{id}": {
      "get": {
        "summary": "Get sub-account",
        "operationId": "getSubAccount",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Sub-account details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubAccountResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Get sub-account. Requires a parent project API key; sub-account API keys receive HTTP 403."
      },
      "patch": {
        "summary": "Update sub-account",
        "operationId": "updateSubAccount",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubAccountUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sub-account updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubAccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Update sub-account. Requires a parent project API key; sub-account API keys receive HTTP 403."
      },
      "delete": {
        "summary": "Deactivate sub-account",
        "description": "Deactivate a sub-account. Remaining balance is returned to the parent team and all API keys are revoked. Requires a parent project API key; sub-account API keys receive HTTP 403.",
        "operationId": "deactivateSubAccount",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Sub-account deactivated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "keysRevoked"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Sub-account deactivated"
                    },
                    "keysRevoked": {
                      "type": "integer",
                      "description": "Number of API keys revoked."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/sub-accounts/{id}/balance": {
      "get": {
        "summary": "Get sub-account spending",
        "description": "Get spending information for a sub-account. Returns the parent team's balance, the sub-account's total spending, and its credit limit (spending cap). Requires a parent project API key; sub-account API keys receive HTTP 403.",
        "operationId": "getSubAccountBalance",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Sub-account balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/sub-accounts/{id}/api-keys": {
      "get": {
        "summary": "List sub-account API keys",
        "operationId": "listSubAccountApiKeys",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "List of API keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SubAccountApiKey"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "List sub-account API keys. Requires a parent project API key; sub-account API keys receive HTTP 403."
      },
      "post": {
        "summary": "Create sub-account API key",
        "operationId": "createSubAccountApiKey",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubAccountApiKeyCreateRequest"
              },
              "example": {
                "name": "Production Key",
                "environment": "live"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created. The full key is only returned once.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "apiKey"
                  ],
                  "properties": {
                    "apiKey": {
                      "type": "object",
                      "required": [
                        "id",
                        "key",
                        "name",
                        "environment"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "key": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "environment": {
                          "type": "string",
                          "enum": [
                            "live",
                            "test"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Create sub-account API key. Requires a parent project API key; sub-account API keys receive HTTP 403."
      }
    },
    "/v1/sub-accounts/{id}/api-keys/{keyId}": {
      "delete": {
        "summary": "Revoke sub-account API key",
        "operationId": "revokeSubAccountApiKey",
        "tags": [
          "Sub-Accounts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SubAccountIdParam"
          },
          {
            "$ref": "#/components/parameters/SubAccountApiKeyIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "API key revoked."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. Sub-account API keys cannot manage sub-accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sub-account or API key not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Revoke sub-account API key. Requires a parent project API key; sub-account API keys receive HTTP 403."
      }
    },
    "/v1/10dlc/brands": {
      "get": {
        "summary": "List 10DLC brands",
        "description": "List 10DLC brand registrations for this project.",
        "operationId": "listTenDlcBrands",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of brands.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TenDlcBrand"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create 10DLC brand",
        "description": "Create a 10DLC brand registration. The brand starts in draft status. Submit it for review using the submit endpoint.",
        "operationId": "createTenDlcBrand",
        "tags": [
          "10DLC"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenDlcBrandCreateRequest"
              },
              "example": {
                "entityType": "PRIVATE_PROFIT",
                "displayName": "Acme Corp",
                "companyName": "Acme Corporation",
                "ein": "12-3456789",
                "email": "compliance@acme.com",
                "phone": "+14155551234",
                "street": "123 Main St",
                "city": "San Francisco",
                "state": "CA",
                "postalCode": "94102",
                "country": "US",
                "website": "https://acme.com",
                "vertical": "Technology"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Brand created in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcBrandResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/brands/use-cases": {
      "get": {
        "summary": "List 10DLC use cases",
        "description": "List available use cases for 10DLC campaign registration.",
        "operationId": "listTenDlcUseCases",
        "tags": [
          "10DLC"
        ],
        "responses": {
          "200": {
            "description": "List of available use cases.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "useCases"
                  ],
                  "properties": {
                    "useCases": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/brands/{brandId}": {
      "get": {
        "summary": "Get 10DLC brand",
        "operationId": "getTenDlcBrand",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcBrandIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Brand details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcBrandResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Brand not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update 10DLC brand",
        "description": "Update a 10DLC brand in draft status. Cannot update after submission.",
        "operationId": "updateTenDlcBrand",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcBrandIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenDlcBrandUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Brand updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcBrandResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or brand already submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Brand not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete 10DLC brand",
        "operationId": "deleteTenDlcBrand",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcBrandIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Brand deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Brand not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/brands/{brandId}/submit": {
      "post": {
        "summary": "Submit 10DLC brand for review",
        "description": "Submit a draft brand to The Campaign Registry (TCR) for vetting. The brand must be in draft status. TCR's one-time $4 brand registration fee is charged from your balance at submission (passed through at cost) and refunded if the carrier rejects the registration. A team that already paid this fee through the compliance flow is not charged again. Campaign registration is billed separately when a campaign is submitted.",
        "operationId": "submitTenDlcBrand",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcBrandIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Brand submitted for review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcBrandResponse"
                }
              }
            }
          },
          "400": {
            "description": "Brand already submitted or invalid status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Brand not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/brands/{brandId}/sync": {
      "post": {
        "summary": "Sync 10DLC brand status",
        "description": "Sync the brand status with the registration provider. Use this to check for approval updates after submission.",
        "operationId": "syncTenDlcBrand",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcBrandIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Brand status synced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcBrandResponse"
                }
              }
            }
          },
          "400": {
            "description": "Brand has not been submitted yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Brand not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/campaigns": {
      "get": {
        "summary": "List 10DLC campaigns",
        "description": "List 10DLC campaign registrations for this project.",
        "operationId": "listTenDlcCampaigns",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "name": "brandId",
            "in": "query",
            "description": "Filter campaigns by brand ID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of campaigns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TenDlcCampaign"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create 10DLC campaign",
        "description": "Create a 10DLC campaign under an existing brand. The campaign starts in draft status. Submit it for carrier review using the submit endpoint.",
        "operationId": "createTenDlcCampaign",
        "tags": [
          "10DLC"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenDlcCampaignCreateRequest"
              },
              "example": {
                "brandId": "brand_abc123",
                "name": "Order Notifications",
                "useCase": "ACCOUNT_NOTIFICATION",
                "description": "Send order status updates and shipping notifications to customers who opted in.",
                "sampleMessages": [
                  "Hi {{name}}, your order #{{order_id}} has shipped! Track it at {{url}}",
                  "Your order #{{order_id}} has been delivered. Thank you for your purchase!"
                ],
                "subscriberOptIn": true,
                "subscriberOptOut": true,
                "subscriberHelp": true,
                "numberPooling": false,
                "directLending": false,
                "embeddedLink": true,
                "embeddedPhone": false,
                "affiliateMarketing": false,
                "ageGated": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Campaign created in draft status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcCampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Brand not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/campaigns/{campaignId}": {
      "get": {
        "summary": "Get 10DLC campaign",
        "operationId": "getTenDlcCampaign",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcCampaignResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update 10DLC campaign",
        "description": "Update a 10DLC campaign in draft status. Cannot update after submission.",
        "operationId": "updateTenDlcCampaign",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenDlcCampaignUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcCampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or campaign already submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete 10DLC campaign",
        "operationId": "deleteTenDlcCampaign",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Campaign deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/campaigns/{campaignId}/submit": {
      "post": {
        "summary": "Submit 10DLC campaign for review",
        "description": "Submit a draft campaign for carrier review. The campaign must be in draft status and its brand must be verified. TCR's one-time registration fee is charged from your balance at submission ($15 for standard use cases, $2 for LOW_VOLUME), passed through at cost and refunded if the carrier rejects it. Once approved, the campaign's monthly TCR fee ($10 standard, $2 LOW_VOLUME) is charged from your balance while the campaign is active — see registrationCostCents and monthlyFeeCents on the campaign object.",
        "operationId": "submitTenDlcCampaign",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign submitted for review.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcCampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Campaign already submitted or invalid status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/campaigns/{campaignId}/sync": {
      "post": {
        "summary": "Sync 10DLC campaign status",
        "description": "Sync the campaign status with the registration provider. Use this to check for approval updates after submission.",
        "operationId": "syncTenDlcCampaign",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign status synced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcCampaignResponse"
                }
              }
            }
          },
          "400": {
            "description": "Campaign has not been submitted yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/campaigns/{campaignId}/phone-numbers": {
      "get": {
        "summary": "List campaign phone number assignments",
        "description": "List phone numbers assigned to a 10DLC campaign.",
        "operationId": "listTenDlcCampaignPhoneNumbers",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "List of phone number assignments.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TenDlcPhoneNumberAssignment"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Assign phone number to campaign",
        "description": "Assign a US phone number to an approved 10DLC campaign. The campaign must be in approved status.",
        "operationId": "assignTenDlcPhoneNumber",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenDlcPhoneNumberAssignRequest"
              },
              "example": {
                "phoneNumberId": "pn_abc123"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Phone number assigned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenDlcAssignmentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Campaign not approved or invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign or phone number not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/10dlc/campaigns/{campaignId}/phone-numbers/{assignmentId}": {
      "delete": {
        "summary": "Unassign phone number from campaign",
        "description": "Remove a phone number assignment from a 10DLC campaign.",
        "operationId": "unassignTenDlcPhoneNumber",
        "tags": [
          "10DLC"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenDlcCampaignIdParam"
          },
          {
            "$ref": "#/components/parameters/TenDlcAssignmentIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Phone number unassigned."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Campaign or assignment not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions": {
      "post": {
        "summary": "Create function",
        "description": "Create a new Zavu Function. The function starts in `draft` status. A dedicated API key is auto-provisioned and injected as the `ZAVU_API_KEY` secret so the function can call back into the Zavu API without manual setup.\n\nProvide `sourceCode` to seed the draft. Call `POST /v1/functions/{functionId}/deploy` afterwards to publish.",
        "operationId": "createFunction",
        "tags": [
          "Functions"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FunctionCreateRequest"
              },
              "example": {
                "slug": "order-bot",
                "name": "Order Bot",
                "description": "Replies to order status questions on WhatsApp.",
                "sourceCode": "import { defineFunction } from '@zavudev/functions';\n\nexport default defineFunction(async (event, ctx) => {\n  ctx.log('received', event.type);\n});\n",
                "dependencies": {
                  "openai": "^4.20.0"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Function created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZavuFunctionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. duplicate slug, invalid dependencies).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}": {
      "get": {
        "summary": "Get function",
        "operationId": "getFunction",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Function details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZavuFunctionResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update function draft",
        "description": "Update an existing function. `sourceCode` / `dependencies` edit the draft without triggering a build — they go live on the next `POST /v1/functions/{functionId}/deploy`. `httpEnabled` is applied to the deployed function immediately, so turning the public endpoint on or off does not require a redeploy.",
        "operationId": "updateFunctionDraft",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FunctionUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Draft updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZavuFunctionResponse"
                }
              }
            }
          },
          "400": {
            "description": "No fields provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete function",
        "description": "Permanently delete a function and cascade: triggers, secrets, deployment history, managed agents+tools, and revoke the auto-provisioned API key. The AWS Lambda + log group are torn down asynchronously.",
        "operationId": "deleteFunction",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Function deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "deleted"
                  ],
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "name": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Cannot delete while a deployment is in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/deploy": {
      "post": {
        "summary": "Deploy function",
        "description": "Publish the function. If `sourceCode` or `dependencies` are provided in the body, they replace the current draft before deployment. Returns immediately with a deployment ID — poll `GET /v1/functions/deployments/{deploymentId}` until status is `active` or `failed`.",
        "operationId": "deployFunction",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FunctionDeployRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Deployment queued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunctionDeploymentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or function in a non-deployable state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/deployments/{deploymentId}": {
      "get": {
        "summary": "Get deployment",
        "description": "Fetch a deployment to poll its status during a deploy.",
        "operationId": "getFunctionDeployment",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionDeploymentIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Deployment details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunctionDeploymentResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Deployment not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/secrets": {
      "get": {
        "summary": "List function secrets",
        "description": "Lists every secret key set on the function. Plaintext is NEVER returned — only the last 4 characters of each value, for visual confirmation.",
        "operationId": "listFunctionSecrets",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Secrets list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "secrets"
                  ],
                  "properties": {
                    "secrets": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "key",
                          "valueLast4"
                        ],
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "key": {
                            "type": "string"
                          },
                          "valueLast4": {
                            "type": "string"
                          },
                          "syncedToAws": {
                            "type": "boolean"
                          },
                          "createdAt": {
                            "type": "number"
                          },
                          "updatedAt": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/secrets/{key}": {
      "put": {
        "summary": "Set function secret",
        "description": "Create or update a secret on a function. Marks the function out-of-sync; the next `POST /deploy` re-publishes the Lambda with the new env. Keys must match `[A-Z_][A-Z0-9_]*` (uppercase env-var style) and cannot start with reserved prefixes (AWS_, LAMBDA_, etc).",
        "operationId": "setFunctionSecret",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          },
          {
            "name": "key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "value"
                ],
                "properties": {
                  "value": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Secret updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "201": {
            "description": "Secret created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid key or value.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Unset function secret",
        "description": "Remove a secret from a function. Doesn't take effect on the running Lambda until the next deploy.",
        "operationId": "unsetFunctionSecret",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          },
          {
            "name": "key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Secret removed."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Secret not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/git-link": {
      "post": {
        "summary": "Link a GitHub repository",
        "description": "Bind a repository to this function so every push to `branch` deploys it. A function holds at most one link; linking again returns 400.\n\n**The server decides how the link authenticates.** If the project has the Zavu GitHub App installed, the link uses that installation: private repositories work and there is nothing to configure in the repository. Otherwise it falls back to a manual link and the response carries a `webhookSecret` you add to the repository yourself. `connection` says which one you got.\n\nThe repository is not checked against GitHub here, because it cannot be: an owner/repo that does not exist, or that the installation cannot see, is accepted and fails on the first deploy with a fetch error.",
        "operationId": "createFunctionGitLink",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "owner",
                  "repo"
                ],
                "properties": {
                  "owner": {
                    "type": "string",
                    "example": "acme"
                  },
                  "repo": {
                    "type": "string",
                    "example": "order-bot"
                  },
                  "branch": {
                    "type": "string",
                    "default": "main"
                  },
                  "rootDir": {
                    "type": "string",
                    "description": "Subdirectory holding the project, for monorepos.",
                    "example": "apps/bot"
                  },
                  "autoDeploy": {
                    "type": "boolean",
                    "default": true
                  }
                }
              },
              "example": {
                "owner": "acme",
                "repo": "order-bot",
                "branch": "main"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Link created. The only response that ever carries `webhookSecret`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GitRepoLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid owner, repo or branch, or the function is already linked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "Get the linked repository",
        "description": "The link and its last deploy. Never returns the webhook secret.",
        "operationId": "getFunctionGitLink",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "The link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GitRepoLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No repository is linked to this function.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update the linked repository",
        "description": "Change the branch, the root directory, or whether pushes deploy. Pass at least one field. `rootDir: null` clears the subdirectory.",
        "operationId": "updateFunctionGitLink",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "branch": {
                    "type": "string"
                  },
                  "rootDir": {
                    "type": "string",
                    "nullable": true
                  },
                  "autoDeploy": {
                    "type": "boolean"
                  }
                }
              },
              "example": {
                "autoDeploy": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GitRepoLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "No fields to update, or invalid values.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No repository is linked to this function.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Unlink the repository",
        "description": "Remove the link. The function and its deployments stay. A manual webhook left in the repository stops being accepted, so remove it there too.",
        "operationId": "deleteFunctionGitLink",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Link removed."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No repository is linked to this function.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/git-link/deploy": {
      "post": {
        "summary": "Deploy the linked branch now",
        "description": "Fetch the linked branch and deploy it without waiting for a push. Returns immediately; follow the outcome with `GET /v1/functions/{functionId}/git-link`, whose `lastStatus` and `lastError` describe the run.",
        "operationId": "deployFunctionGitLink",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          }
        ],
        "responses": {
          "202": {
            "description": "Deploy scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "scheduled"
                  ],
                  "properties": {
                    "scheduled": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No repository is linked to this function.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A deploy for this link is already running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/functions/{functionId}/logs": {
      "get": {
        "summary": "Tail function logs",
        "description": "Fetch invocation logs for a function. Logs are paginated via `nextToken`. Pass `startTime` / `endTime` (Unix epoch milliseconds) to bound the window, or `filterPattern` to filter messages.",
        "operationId": "tailFunctionLogs",
        "tags": [
          "Functions"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FunctionIdParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "nextToken",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "startTime",
            "in": "query",
            "description": "Start of the log window in Unix epoch milliseconds.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "endTime",
            "in": "query",
            "description": "End of the log window in Unix epoch milliseconds.",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "filterPattern",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Log events.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunctionLogsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Function not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/calls": {
      "post": {
        "summary": "Place a voice call",
        "description": "Place an outbound voice call answered by the voice agent configured on the sender. Zavu dials the recipient and runs the conversation through its managed voice pipeline (speech recognition, the agent's LLM, and speech synthesis, with real-time interruption handling).\n\n**Requirements:**\n- The Voice Agents feature must be enabled for your team (otherwise `403`).\n- The sender's agent must have `voice.enabled` set to `true`.\n- Not available with test-mode API keys.\n\n**Billing:** Voice calls are billed per minute of connected time plus telephony, deducted from your prepaid balance. A short-duration estimate is reserved when the call is placed; you are charged for the actual duration when the call ends.",
        "operationId": "createCall",
        "tags": [
          "Voice Agents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoiceCallCreateRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Outbound call with the default sender",
                  "value": {
                    "to": "+56912345678"
                  }
                },
                "language": {
                  "summary": "Outbound call in a different language",
                  "value": {
                    "to": "+56912345678",
                    "language": "es-ES"
                  }
                },
                "full": {
                  "summary": "Outbound call with overrides",
                  "value": {
                    "to": "+56912345678",
                    "senderId": "sender_12345",
                    "greeting": "Hi, this is Acme calling about your appointment.",
                    "language": "en-US",
                    "maxDurationMinutes": 10,
                    "metadata": {
                      "campaign": "appointment_reminders"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Call accepted and dialing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceCallResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, the sender's agent does not have voice enabled, or voice calls are not available in test mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "voice_not_enabled": {
                    "summary": "Agent voice not enabled",
                    "value": {
                      "code": "invalid_request",
                      "message": "The sender's agent does not have voice enabled"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "insufficient_balance",
                  "message": "Insufficient balance to place this call. Please add funds to continue."
                }
              }
            }
          },
          "403": {
            "description": "Voice Agents is not enabled for this team.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "forbidden",
                  "message": "Voice Agents is not enabled for this team"
                }
              }
            }
          },
          "404": {
            "description": "Sender or agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List voice calls",
        "description": "List voice calls for this project, most recent first. Transcripts are omitted from the list; fetch a single call to get its transcript.",
        "operationId": "listCalls",
        "tags": [
          "Voice Agents"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/VoiceCallStatus"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/VoiceCallDirection"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of voice calls.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VoiceCall"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Voice Agents is not enabled for this team.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/calls/{callId}": {
      "get": {
        "summary": "Get voice call",
        "description": "Retrieve a single voice call, including its full transcript once the conversation has produced turns.",
        "operationId": "getCall",
        "tags": [
          "Voice Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CallIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Voice call details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceCallResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Voice Agents is not enabled for this team.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Call not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/calls/{callId}/hangup": {
      "post": {
        "summary": "Hang up a voice call",
        "description": "End an active voice call. The call must still be ringing or in progress. Not available with test-mode API keys.",
        "operationId": "hangupCall",
        "tags": [
          "Voice Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CallIdParam"
          }
        ],
        "responses": {
          "202": {
            "description": "Hang up accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceCallResponse"
                }
              }
            }
          },
          "400": {
            "description": "The call is not active and cannot be hung up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Voice Agents is not enabled for this team.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Call not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agent-templates": {
      "get": {
        "summary": "List factory agents",
        "description": "List the factory agents available to scaffold with `npx zavudev agents pull`. Each entry is a ready-made voice or text agent (system prompt, skills, and — for voice agents — a co-located voice config).",
        "operationId": "listAgentTemplates",
        "tags": [
          "Agents"
        ],
        "responses": {
          "200": {
            "description": "List of factory agents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentTemplateSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agent-templates/{templateId}": {
      "get": {
        "summary": "Get a factory agent",
        "description": "Fetch a single factory agent fully rendered: the function files to scaffold (an `index.ts` that declares the agent with `defineAgent` and its skills with `defineTool`) plus the secrets it needs. This is what `npx zavudev agents pull <id>` writes to disk before `npx zavudev deploy`.",
        "operationId": "getAgentTemplate",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "fermi"
          }
        ],
        "responses": {
          "200": {
            "description": "Rendered factory agent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "template"
                  ],
                  "properties": {
                    "template": {
                      "$ref": "#/components/schemas/AgentTemplate"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/email-domains": {
      "post": {
        "summary": "Add an email domain",
        "description": "Add a domain to send email from. Returns the DNS records to publish (DKIM CNAMEs are required; SPF, DMARC, and MAIL FROM are recommended). Publish them at your DNS provider, then verify.",
        "operationId": "addEmailDomain",
        "tags": [
          "Email Domains"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Bare domain, e.g. example.com.",
                    "example": "example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain added.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "domain"
                  ],
                  "properties": {
                    "domain": {
                      "$ref": "#/components/schemas/EmailDomain"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid domain or setup failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "summary": "List email domains",
        "operationId": "listEmailDomains",
        "tags": [
          "Email Domains"
        ],
        "responses": {
          "200": {
            "description": "Email domains.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmailDomain"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/email-domains/{domainId}": {
      "get": {
        "summary": "Get an email domain",
        "description": "Fetch a domain with its DNS records and current status.",
        "operationId": "getEmailDomain",
        "tags": [
          "Email Domains"
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "domain"
                  ],
                  "properties": {
                    "domain": {
                      "$ref": "#/components/schemas/EmailDomain"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Domain not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Remove an email domain",
        "operationId": "deleteEmailDomain",
        "tags": [
          "Email Domains"
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Domain removed."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Domain not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/email-domains/{domainId}/verify": {
      "post": {
        "summary": "Verify an email domain",
        "description": "Re-check the domain's published DNS records and refresh its status.",
        "operationId": "verifyEmailDomain",
        "tags": [
          "Email Domains"
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Verification re-checked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "domain"
                  ],
                  "properties": {
                    "domain": {
                      "$ref": "#/components/schemas/EmailDomain"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Domain not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/telegram": {
      "post": {
        "summary": "Connect Telegram",
        "description": "Connect a Telegram bot to a sender. Provide the bot token from @BotFather; Zavu validates it, registers the webhook, and routes the sender's Telegram messages through it.",
        "operationId": "connectSenderTelegram",
        "tags": [
          "Senders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "botToken"
                ],
                "properties": {
                  "botToken": {
                    "type": "string",
                    "description": "Bot token from @BotFather."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Telegram connected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "telegram"
                  ],
                  "properties": {
                    "telegram": {
                      "type": "object",
                      "required": [
                        "connected"
                      ],
                      "properties": {
                        "connected": {
                          "type": "boolean"
                        },
                        "botUsername": {
                          "type": "string"
                        },
                        "botId": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid bot token or request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Disconnect Telegram",
        "description": "Disconnect Telegram from a sender and remove the webhook.",
        "operationId": "disconnectSenderTelegram",
        "tags": [
          "Senders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Telegram disconnected."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agents": {
      "get": {
        "summary": "List agents",
        "description": "Every agent in the project, newest first — including agents that are not connected to any sender yet, which the sender-scoped routes cannot reach. Each item carries `senderIds`, the senders the agent answers on.",
        "operationId": "listAgents",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of agents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Agent"
                      }
                    },
                    "nextCursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "summary": "Create a standalone agent",
        "description": "Create an agent without a sender. It is created disabled; connect a sender and enable it when you are ready for it to answer.\n\n**Sub-resources.** An agent's tools, flows and knowledge bases are reachable at `/v1/agents/{agentId}/tools`, `/v1/agents/{agentId}/flows` and `/v1/agents/{agentId}/knowledge-bases`, mirroring the sender-scoped routes documented under `/v1/senders/{senderId}/agent/...` exactly. Use the agent-scoped form while the agent has no sender: the sender-scoped one cannot address it.",
        "operationId": "createStandaloneAgent",
        "tags": [
          "Agents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentCreateStandaloneRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Agent created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "agent"
                  ],
                  "properties": {
                    "agent": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agents/{agentId}": {
      "get": {
        "summary": "Get an agent",
        "operationId": "getAgentById",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AgentIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Agent details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "agent"
                  ],
                  "properties": {
                    "agent": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "patch": {
        "summary": "Update an agent",
        "operationId": "updateAgentById",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AgentIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Agent updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "agent"
                  ],
                  "properties": {
                    "agent": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "delete": {
        "summary": "Delete an agent",
        "operationId": "deleteAgentById",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AgentIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Agent deleted."
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agents/{agentId}/test": {
      "post": {
        "summary": "Test an agent",
        "description": "Run the agent's prompt, model and knowledge base against a message and return the reply instead of delivering it. Writes nothing and charges nothing, so it is safe to call repeatedly while iterating on a prompt.\n\nNote that a dry run never **executes** tools — running them would cause real side effects. Live conversations on every channel do call them. When the agent has enabled tools, that gap is reported in `warnings` rather than silently producing an answer that looks like a tool call happened.",
        "operationId": "testAgent",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AgentIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentTestRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The agent's reply.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentTestResponse"
                }
              }
            }
          },
          "400": {
            "description": "message is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Sender or agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agents/{agentId}/senders": {
      "post": {
        "summary": "Connect a sender to an agent",
        "description": "Make the agent answer on this sender. An agent can serve several senders; a sender answers with at most one agent, so connecting one that is already in use returns `400` naming the agent that holds it.",
        "operationId": "attachAgentSender",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AgentIdParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "senderId"
                ],
                "properties": {
                  "senderId": {
                    "type": "string",
                    "description": "Sender to connect."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sender connected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "agent"
                  ],
                  "properties": {
                    "agent": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "senderId missing, or the sender already answers with another agent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent or sender not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agents/{agentId}/senders/{senderId}": {
      "delete": {
        "summary": "Disconnect a sender from an agent",
        "description": "Stop the agent answering on this sender. The agent's primary sender is part of the agent itself and cannot be disconnected here.",
        "operationId": "detachAgentSender",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AgentIdParam"
          },
          {
            "$ref": "#/components/parameters/SenderIdParam"
          }
        ],
        "responses": {
          "204": {
            "description": "Sender disconnected."
          },
          "400": {
            "description": "That sender is the agent's primary, or is not connected to it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Agent not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/agents/voices": {
      "get": {
        "summary": "List agent voices",
        "description": "The voices an agent can speak with, for `voice.ttsVoiceId`. Filter by `language` to get the ones that speak it; a voice can still be used with `language: auto`, where the agent follows the caller and keeps the chosen voice.",
        "operationId": "listAgentVoices",
        "tags": [
          "Agents"
        ],
        "parameters": [
          {
            "name": "language",
            "in": "query",
            "description": "BCP-47 tag (`en`, `es`, `pt-BR`). Omit, or pass `auto`, for every voice.",
            "schema": {
              "type": "string",
              "example": "es"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Available voices.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items",
                    "languages"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "name",
                          "language"
                        ],
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Value for `voice.ttsVoiceId`.",
                            "example": "aura-2-celeste-es"
                          },
                          "name": {
                            "type": "string",
                            "example": "celeste"
                          },
                          "language": {
                            "type": "string",
                            "example": "es"
                          }
                        }
                      }
                    },
                    "languages": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Languages an agent can be pinned to. `auto` follows the caller."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Voices in the catalog, before filtering."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/v1/senders/{senderId}/agent/tools/{toolId}/webhook/secret": {
      "post": {
        "summary": "Rotate a tool's webhook secret",
        "description": "Generate a new signing secret for this tool. The previous one stops working on the next call, with no overlap, so update your endpoint first. The tool keeps its id, so flows that reference it by name are unaffected.",
        "operationId": "rotateAgentToolWebhookSecret",
        "tags": [
          "Agent Tools"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderIdParam"
          },
          {
            "$ref": "#/components/parameters/ToolIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "New secret generated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecretResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tool not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    }
  }
}
