> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zavu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Send broadcast

> Start sending the broadcast immediately or schedule for later.

**Sending a broadcast needs no account verification.** Identity and business verification raise daily ceilings; neither is a permission to broadcast, on any channel. What stands in front of a broadcast is the content review below, and it applies to every send path — dashboard, API and CLI. Drafts can be created, edited and kept freely.

**Daily ceilings apply per recipient.** Each message a broadcast sends counts against the channel's daily ceiling (see `POST /v1/messages`). Once the ceiling is reached, the remaining recipients are marked `failed` with `errorCode` `DAILY_LIMIT_EXCEEDED`; they are not retried the next day.

**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 review passes it, unless the review asks for a person. Every other channel moves to `pending_admin_review` and waits for a person. A broadcast the review refuses lands on `rejected`: use PATCH to edit the content then call POST /retry-review, or escalate it for a manual review.

A broadcast is read once, on its own text, rather than per recipient. While an account's sending is suspended its recipients fail individually with `errorCode` `SENDING_SUSPENDED`; see `POST /v1/messages`.

Calling 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.



## OpenAPI

````yaml /openapi.json post /v1/broadcasts/{broadcastId}/send
openapi: 3.0.3
info:
  title: Zavu Unified Messaging Layer API
  version: 0.2.0
  description: >
    Unified multi-channel messaging API for Zavu.


    Supported channels:

    - **SMS**: Simple text messages

    - **WhatsApp**: Rich messaging with media, buttons, lists, CTA URL buttons,
    location requests, and templates

    - **Telegram**: Bot messaging with text, media, and interactive elements

    - **Email**: Transactional emails via Amazon SES


    Design goals:

    - Simple `send()` entrypoint for developers

    - Project-level authentication via Bearer token

    - Support for all WhatsApp message types (text, image, video, audio,
    document, sticker, location, contact, buttons, list, cta_url,
    location_request, reaction, template)

    - If a non-text message type is sent, WhatsApp channel is used automatically

    - 24-hour WhatsApp conversation window enforcement

    - Universal `to` field accepts phone numbers (E.164), email addresses, or
    numeric chat IDs (Telegram/Instagram/Messenger)
servers:
  - url: https://api.zavu.dev
security:
  - bearerAuth: []
paths:
  /v1/broadcasts/{broadcastId}/send:
    post:
      summary: Send broadcast
      description: >-
        Start sending the broadcast immediately or schedule for later.


        **Sending a broadcast needs no account verification.** Identity and
        business verification raise daily ceilings; neither is a permission to
        broadcast, on any channel. What stands in front of a broadcast is the
        content review below, and it applies to every send path — dashboard, API
        and CLI. Drafts can be created, edited and kept freely.


        **Daily ceilings apply per recipient.** Each message a broadcast sends
        counts against the channel's daily ceiling (see `POST /v1/messages`).
        Once the ceiling is reached, the remaining recipients are marked
        `failed` with `errorCode` `DAILY_LIMIT_EXCEEDED`; they are not retried
        the next day.


        **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 review passes it, unless the review asks for a
        person. Every other channel moves to `pending_admin_review` and waits
        for a person. A broadcast the review refuses lands on `rejected`: use
        PATCH to edit the content then call POST /retry-review, or escalate it
        for a manual review.


        A broadcast is read once, on its own text, rather than per recipient.
        While an account's sending is suspended its recipients fail individually
        with `errorCode` `SENDING_SUSPENDED`; see `POST /v1/messages`.


        Calling 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.


            A WhatsApp broadcast whose template Meta has not approved yet is
            refused here with code `template_not_approved`. Because a WhatsApp
            broadcast needs no account verification, this is the only review it
            passes through: retry once the template is approved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                template_not_approved:
                  summary: WhatsApp template awaiting Meta approval
                  value:
                    code: template_not_approved
                    message: >-
                      This broadcast can't be sent yet. Its WhatsApp template is
                      still awaiting Meta approval.
                no_contacts:
                  summary: Broadcast has no recipients
                  value:
                    code: invalid_request
                    message: >-
                      This broadcast has no recipients yet. Add recipients
                      before sending.
        '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
        '404':
          description: Broadcast not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  parameters:
    BroadcastIdParam:
      name: broadcastId
      in: path
      required: true
      schema:
        type: string
  schemas:
    BroadcastSendRequest:
      type: object
      properties:
        scheduledAt:
          type: string
          format: date-time
          description: Schedule for future delivery. Omit to send immediately.
    BroadcastResponse:
      type: object
      required:
        - broadcast
      properties:
        broadcast:
          $ref: '#/components/schemas/Broadcast'
    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
    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
        sentCount:
          type: integer
          description: >-
            Recipients whose message the provider accepted, without a confirmed
            delivery yet. Channels that never report delivery keep their
            recipients here.
        deliveredCount:
          type: integer
          description: Recipients with confirmed delivery to the device.
        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).
    BroadcastStatus:
      type: string
      description: >-
        Current status of the broadcast.


        - `draft`: editable, not submitted.

        - `pending_review`: in automated content review.

        - `pending_admin_review`: passed automated review and waits for a person
        at Zavu. Every channel except email (and WhatsApp on an approved
        template, which skips review) stops here.

        - `approved`: cleared to send; `POST /v1/broadcasts/{broadcastId}/send`
        starts it.

        - `rejected`: refused by automated review. Edit and retry the review, or
        escalate.

        - `escalated`: a manual review was requested.

        - `rejected_final`: refused by a person; cannot be retried.

        - `scheduled`, `sending`, `paused`, `completed`, `cancelled`, `failed`:
        delivery lifecycle.
      enum:
        - draft
        - pending_review
        - pending_admin_review
        - approved
        - rejected
        - escalated
        - rejected_final
        - scheduled
        - sending
        - paused
        - completed
        - cancelled
        - failed
    BroadcastChannel:
      type: string
      description: >-
        Broadcast delivery channel. Use 'smart' for per-contact intelligent
        routing.
      enum:
        - smart
        - sms
        - sms_oneway
        - whatsapp
        - telegram
        - email
    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
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.