Zavu Senders API

The Senders API from Zavu — 5 operation(s) for senders.

OpenAPI Specification

zavu-senders-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Zavu Unified Messaging Layer 10DLC Senders 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, 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, 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: []
tags:
- name: Senders
paths:
  /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: []
      tags:
      - Senders
    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: []
      tags:
      - Senders
  /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: []
      tags:
      - Senders
    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: []
      tags:
      - Senders
    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: []
      tags:
      - Senders
  /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: []
      tags:
      - Senders
  /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: []
      tags:
      - Senders
    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: []
      tags:
      - Senders
  /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: []
      tags:
      - Senders
components:
  schemas:
    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
    SenderUpdateRequest:
      type: object
      properties:
        name:
          type: string
        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.
    WhatsAppBusinessProfileResponse:
      type: object
      required:
      - profile
      properties:
        profile:
          $ref: '#/components/schemas/WhatsAppBusinessProfile'
    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'
    WebhookEvent:
      type: string
      description: 'Type of event that triggers the webhook.


        **Message lifecycle events:**

        - `message.queued`: Message created and queued for sending. `data.status` = `queued`

        - `message.sent`: Message accepted by the provider. `data.status` = `sent`

        - `message.delivered`: Message delivered to recipient. `data.status` = `delivered`

        - `message.read`: Message was read by the recipient (WhatsApp only). `data.status` = `read`

        - `message.failed`: Message failed to send. `data.status` = `failed`


        **Inbound events:**

        - `message.inbound`: New message received from a contact. 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.

        - `message.status`: A contact posted a WhatsApp status/story (currently WhatsApp Alternative only). It is NOT a conversation message and never enters the inbox — it is delivered only if you subscribe to `message.status`. `data` carries `from` (the author in E.164), `messageType` (`text`, `image`, `video`, `audio`), `text` (caption/text when present), `mimetype` (for media stories), and `providerTimestamp`. Media bytes are not included.

        - `message.unsupported`: Received a message type that is not supported


        **Broadcast events:**

        - `broadcast.status_changed`: Broadcast status changed (pending_review, approved, rejected, sending, completed, cancelled)


        **Other events:**

        - `conversation.new`: New conversation started with a contact

        - `template.status_changed`: WhatsApp template approval status changed


        **Partner events:**

        - `invitation.status_changed`: A partner invitation status changed (pending, in_progress, completed, cancelled)


        **Custom domain events:**

        - `domain.verified`: A custom email domain passed verification (DKIM, and SPF/DMARC/MAIL FROM if enhanced records are enabled)

        - `domain.failed`: A custom email domain failed verification or is partially verified'
      enum:
      - message.queued
      - message.sent
      - message.delivered
      - message.read
      - message.failed
      - message.inbound
      - message.status
      - message.unsupported
      - broadcast.status_changed
      - conversation.new
      - template.status_changed
      - invitation.status_changed
      - domain.verified
      - domain.failed
    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
    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'
        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
    WebhookSecretResponse:
      type: object
      required:
      - secret
      properties:
        secret:
          type: string
          description: The new webhook secret.
          example: whsec_abc123...
    SenderWebhook:
      type: object
      description: Webhook configuration for the sender.
      required:
      - url
      - events
      - active
      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
    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
    SenderCreateRequest:
      type: object
      description: Create a sender. Provide `phoneNumber` for an SMS/WhatsApp sender, or `emailAddress` (with a verified email domain) for an email sender — at least one is required.
      required:
      - name
      properties:
        name:
          type: string
        phoneNumber:
          type: string
          description: Phone number in E.164 format. Required for phone-based channels (SMS, WhatsApp). Omit for an email-only sender.
        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.
    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'
  parameters:
    SenderIdParam:
      name: senderId
      in: path
      required: true
      schema:
        type: string
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT