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

# Append a batch of recipients to a campaign by ID.

> Only campaigns with status "draft" can be modified.
Meant for recipient lists that are too large for a single request:
call this repeatedly and set "is_last" on the final batch.
Send "reset" with the first batch to replace the existing list.
Phone numbers are normalized, duplicates inside the batch and numbers
already stored for the campaign are skipped. A batch can therefore be
sent again after a timeout without creating duplicates.




## OpenAPI

````yaml /openapi/chat-client.yaml post /whatsapp/campaigns/{id}/recipients
openapi: 3.0.3
info:
  version: 1.0.0
  title: HealviChat Client API
servers:
  - url: https://{tenant_domain}/third-party/v1
    variables:
      tenant_domain:
        default: your-tenant.onhealvi.com
        description: Your tenant domain
security:
  - bearerAuth: []
paths:
  /whatsapp/campaigns/{id}/recipients:
    post:
      tags:
        - whatsapp
      summary: Append a batch of recipients to a campaign by ID.
      description: |
        Only campaigns with status "draft" can be modified.
        Meant for recipient lists that are too large for a single request:
        call this repeatedly and set "is_last" on the final batch.
        Send "reset" with the first batch to replace the existing list.
        Phone numbers are normalized, duplicates inside the batch and numbers
        already stored for the campaign are skipped. A batch can therefore be
        sent again after a timeout without creating duplicates.
      parameters:
        - in: path
          name: id
          schema:
            type: integer
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppendWhatsappCampaignRecipients'
      responses:
        '200':
          description: |
            Success. Intermediate batches return the result of the batch.
            The final batch ("is_last" = true) returns the campaign itself
            with the batch result in "meta".
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    properties:
                      data:
                        $ref: >-
                          #/components/schemas/WhatsappCampaignRecipientsBatchResult
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/WhatsappCampaign'
                      meta:
                        $ref: >-
                          #/components/schemas/WhatsappCampaignRecipientsBatchResult
components:
  schemas:
    AppendWhatsappCampaignRecipients:
      type: object
      required:
        - recipients
      properties:
        recipients:
          type: array
          maxItems: 5000
          items:
            $ref: '#/components/schemas/UpsertWhatsappCampaignRecipient'
        reset:
          type: boolean
          default: false
          description: |
            Delete all recipients currently stored on the campaign before
            inserting this batch. Send it with the first batch to restart
            an upload from scratch.
        is_last:
          type: boolean
          default: false
          description: >
            Marks the final batch of an upload. Finalizes the upload, writes a

            campaign log entry and returns the campaign instead of the batch
            result.
    WhatsappCampaignRecipientsBatchResult:
      type: object
      properties:
        received:
          type: integer
          description: Number of recipients in the request.
          example: 1000
        inserted:
          type: integer
          description: Number of recipients actually stored.
          example: 987
        skipped:
          type: integer
          description: |
            Recipients dropped as duplicates, either within the batch itself or
            because the phone number is already stored on the campaign.
          example: 13
        total:
          type: integer
          description: Total number of recipients on the campaign after this batch.
          example: 4187
        finalized:
          type: boolean
          description: Whether this batch was sent with "is_last".
          example: false
    WhatsappCampaign:
      description: WhatsApp campaign (marketing).
      type: object
      properties:
        id:
          type: integer
          description: Internal ID.
        name:
          description: Name of campaign.
          type: string
        agent_id:
          description: ID of connected WhatsApp agent.
          type: string
        wa_template_id:
          description: ID of connected WhatsApp template.
          type: string
        status:
          description: Status of campaign.
          type: string
          enum:
            - ready
            - in_progress
            - paused
            - done
            - canceled
        components:
          description: >
            Array of objects describing how to fill variables within the
            specified template.

            If there are no variables, set this to an empty array.

            Format is defined by WhatsApp. See `components` under
            https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-message-templates
          type: array
          items:
            type: object
        start_at:
          description: >
            Datetime when to start sending the campaign. Field is only relevant
            if status is "in_progress".

            Field is also used when messaging limit is reached for the day.
            Campaign will wait till next day

            same time and continue sending.
          type: string
          format: date-time
          nullable: true
          example: '2023-01-01T12:00:00Z'
        send_from:
          description: >
            Together with send_until: time window to send the campaign. Can be
            used such that customers do not receive

            messages in the middle of the night.
          type: string
          example: '00:00:00'
        send_until:
          description: See send_from.
          type: string
          example: '23:59:59'
        assign_bot_id:
          description: |
            Optional ID of bot which will be assigned to the conversation.
            Existing running bot will be stopped and a new one will be started.
          type: integer
          nullable: true
        assign_user_id:
          description: |
            Optional ID of user the conversation will be assigned to.
          type: integer
          nullable: true
        assign_folder_id:
          description: |
            Optional ID of folder the conversation will be assigned to.
          type: integer
          nullable: true
        assign_tag_id:
          description: |
            Optional ID of tag the profile will be assigned to.
          type: integer
          nullable: true
        assign_group_id:
          description: |
            Optional ID of tag the profile will be assigned to.
          type: integer
          nullable: true
        resume_at:
          description: >
            When messaging limit is reached for the day, this field will be set
            to the datetime when the

            campaign will resume.
          type: string
          format: date-time
          nullable: true
          example: '2023-01-01T12:00:00Z'
        finished_at:
          description: |
            Filled when campaign is finished.
          type: string
          format: date-time
          nullable: true
          example: '2023-01-01T12:00:00Z'
        created_at:
          description: |
            When the campaign was created.
          type: string
          format: date-time
          nullable: true
          example: '2023-01-01T12:00:00Z'
        updated_at:
          description: |
            When the campaign was updated.
          type: string
          format: date-time
          nullable: true
          example: '2023-01-01T12:00:00Z'
        recipients_count:
          description: Total number of attached recipients.
          type: integer
        latest_statistics:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/WhatsappCampaignStatistics'
    UpsertWhatsappCampaignRecipient:
      type: object
      required:
        - phone_number
        - placeholders
      properties:
        profile_id:
          type: integer
          nullable: true
          description: ID of an existing profile the recipient belongs to.
        name:
          type: string
          nullable: true
          example: Jane Doe
        phone_number:
          type: string
          maxLength: 128
          description: |
            Formatting characters ("+()-_", space) and a leading "00" are
            stripped, the number is stored as "+<digits>".
          example: '+49123456789'
        placeholders:
          type: object
          additionalProperties:
            type: string
          description: |
            Values for the placeholders of the campaign template, keyed by
            placeholder name. Send an empty object when the template has none.
          example:
            first_name: Jane
            order_id: '12345'
    WhatsappCampaignStatistics:
      description: Statistics of a WhatsApp campaign. Fetched hourly.
      type: object
      properties:
        id:
          type: integer
        campaign_id:
          type: integer
        datetime:
          type: string
          format: date-time
          example: '2023-01-01T12:00:00Z'
        recipients_count:
          type: integer
        to_send_count:
          type: integer
        to_send_percent:
          type: number
        sent_count:
          type: integer
        sent_percent:
          type: number
        delivered_count:
          type: integer
        delivered_percent:
          type: number
        read_count:
          type: integer
        read_percent:
          type: number
        error_count:
          type: integer
        error_percent:
          type: number
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````