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

# Bulk Send

> Send templates in bulk to multiple recipients and check the status of your campaigns

Use this function to send templates in bulk to your customers. The API will handle delivery to recipients from a column-based file.

Sending templates in bulk allows you to send a predefined template with different values related to each customer, so you can select dynamic information from a source such as a file, to automate and send your campaign easily.

***

## Template guidelines

The source file must be created following these specifications:

### File format

Only files with the `.CSV` extension are supported.

### Header

The first row of the file must define the column names (header). Follow these rules for the header:

* Avoid **blank spaces** in column names.
* Do not use **special characters** or **punctuation marks** (e.g., `!, $, %, &, *, etc.`).
* Use only **letters**, **numbers**, and **underscores** (`_`) if necessary.

**Correct:** `phone_number`, `customer_name`, `order_amount`

**Incorrect:** `phone number`, `customer-name!`, `order#amount`

### First column

The first column must contain the phone numbers of the recipients. It is mandatory to include the international code without the `+` symbol (for example, for a number in Ecuador, write `PHONE_NUMBER`).

### Remaining columns

The other columns will be used for the dynamic values of the parameters (template personalization).

***

## Example

If your template contains the following content:

```
Your order {{1}} for a total of {{2}} is confirmed. The expected delivery is {{3}}.
```

The CSV file would be:

| phone\_number    | param\_1 | param\_2 | param\_3   |
| ---------------- | -------- | -------- | ---------- |
| PHONE\_NUMBER    | A12345   | \$250.00 | December 1 |
| PHONE\_NUMBER\_2 | B67890   | \$100.50 | December 2 |
| PHONE\_NUMBER\_3 | C22345   | \$50.00  | December 3 |

<Note>
  The CSV file must be encoded in UTF-8.
</Note>

***

## Send HSM from file

```
POST https://api.jelou.ai/v1/hsm/file
```

***

## File upload options

There are two ways to provide the CSV file with recipient information:

1. **Using a public URL**: You can provide the URL to the CSV file that is publicly available. In this case, the request body must be in JSON format.

2. **Uploading the file**: Alternatively, you can attach the CSV file directly to the request. In this case, the request body must be in `multipart/form-data` format.

***

## Body parameters

| Property           | Type   | Description                                                                                                                              | Required    |
| ------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **campaignName**   | string | Name assigned to the campaign being sent.                                                                                                | Yes         |
| **elementName**    | string | Template name. Must have **approved** status by WhatsApp.                                                                                | Yes         |
| **botId**          | string | Unique identifier of the bot sending the template.                                                                                       | Yes         |
| **params**         | array  | Array of objects with the parameter number and the corresponding CSV column. If the template has no parameters, the array must be empty. | Yes         |
| **type**           | string | Template type: `text`, `image`, `document`, `video`. Defaults to `text`.                                                                 | No          |
| **mediaUrl**       | string | Public URL of the media file. Required for image, video, or document templates.                                                          | Conditional |
| **fileUrl**        | string | Public URL of the CSV file. Required if the file is not uploaded directly.                                                               | Conditional |
| **file**           | file   | Attached CSV file. Required if `fileUrl` is not used.                                                                                    | Conditional |
| **buttonPayloads** | array  | Array of objects for quick reply buttons with workflows.                                                                                 | No          |
| **actions**        | object | Actions related to the template.                                                                                                         | No          |
| **scheduledAt**    | date   | Date and time in UTC when the campaign will be sent.                                                                                     | No          |

***

## Request examples

<AccordionGroup>
  <Accordion title="Send from public URL (JSON)">
    ```bash theme={null}
    curl --request POST \
      --url https://api.jelou.ai/v1/hsm/file \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "campaignName": "campaign_name",
        "botId": "BOT_ID",
        "elementName": "ELEMENT_NAME",
        "params": [
          {"param": 1, "column": "customer_name"}
        ],
        "mediaUrl": "https://cdn.example.com/image.png",
        "type": "image",
        "fileUrl": "https://cdn.example.com/campaign.csv",
        "buttonPayloads": [
          {"type": "edge", "action": "Yes", "skillId": "1"}
        ]
      }'
    ```
  </Accordion>

  <Accordion title="Send with attached file (multipart/form-data)">
    ```bash theme={null}
    curl --request POST \
      --url https://api.jelou.ai/v1/hsm/file \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --form campaignName=campaign_name \
      --form botId=BOT_ID \
      --form elementName=ELEMENT_NAME \
      --form 'buttonPayloads=[{"type":"edge","action":"Yes","skillId":"1"},{"type":"edge","action":"Reschedule","skillId":"2"},{"type":"edge","action":"Cancel","skillId":"3"}]' \
      --form file=@/local/path/campaign.csv \
      --form 'params=[]'
    ```
  </Accordion>
</AccordionGroup>

***

## Send responses

<AccordionGroup>
  <Accordion title="200 - Successful response">
    ```json theme={null}
    {
      "message": ["Campaign has been created."],
      "status": "success"
    }
    ```
  </Accordion>

  <Accordion title="400 - Bad Request">
    ```json theme={null}
    {
      "message": ["Invalid CSV format"],
      "status": "failed"
    }
    ```
  </Accordion>

  <Accordion title="401 - Unauthorized">
    ```json theme={null}
    {
      "message": "Authentication failed"
    }
    ```
  </Accordion>

  <Accordion title="422 - Unprocessable Entity">
    ```json theme={null}
    {
      "message": ["Template not found or not approved"],
      "status": "failed"
    }
    ```
  </Accordion>
</AccordionGroup>

***

## params structure

Each element in the `params` array is an object that contains:

```json theme={null}
[
  {"param": 1, "column": "customer_name"},
  {"param": 2, "column": "order_amount"}
]
```

* **param**: Parameter number in the template (1, 2, 3...).
* **column**: Name of the column in the CSV file from which values will be extracted.

***

## buttonPayloads structure

For templates with quick reply buttons that activate workflows:

```json theme={null}
[
  {"type": "edge", "action": "Yes", "skillId": "1"},
  {"type": "edge", "action": "Reschedule", "skillId": "2"},
  {"type": "edge", "action": "Cancel", "skillId": "3"}
]
```


## OpenAPI

````yaml POST /v1/hsm/file
openapi: 3.1.0
info:
  title: Jelou API
  description: >-
    API for the Jelou platform. Send messages, manage campaigns, handle
    conversations, users, databases, and widgets.
  version: 1.0.0
servers:
  - url: https://api.jelou.ai
    description: Production server
security:
  - basicAuth: []
tags:
  - name: Messages
    description: Send messages to users
  - name: Campaigns
    description: HSM campaigns and templates
  - name: Conversations
    description: Chat history and metrics
  - name: Users
    description: User state and cache management
  - name: Resources
    description: Media resource management
  - name: Datum
    description: Database CRUD operations
  - name: Widget
    description: Widget and room management
  - name: PMA Custom
    description: External support panel integration
paths:
  /v1/hsm/file:
    post:
      tags:
        - Campaigns
      summary: Send Bulk HSM
      description: Send HSM templates in bulk to multiple recipients using a CSV file.
      operationId: sendBulkHSM
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkHSMJsonRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/BulkHSMFormRequest'
      responses:
        '200':
          description: Campaign created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkHSMResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
components:
  schemas:
    BulkHSMJsonRequest:
      type: object
      required:
        - campaignName
        - elementName
        - botId
        - params
      properties:
        campaignName:
          type: string
        elementName:
          type: string
        botId:
          type: string
        params:
          type: array
          items:
            $ref: '#/components/schemas/CSVParam'
        type:
          type: string
          enum:
            - text
            - image
            - document
            - video
          default: text
        mediaUrl:
          type: string
          format: uri
        fileUrl:
          type: string
          format: uri
        buttonPayloads:
          type: array
          items:
            type: object
        actions:
          type: object
        scheduledAt:
          type: string
          format: date-time
    BulkHSMFormRequest:
      type: object
      required:
        - campaignName
        - elementName
        - botId
        - params
        - file
      properties:
        campaignName:
          type: string
        elementName:
          type: string
        botId:
          type: string
        params:
          type: string
          description: JSON string of params array
        file:
          type: string
          format: binary
        buttonPayloads:
          type: string
          description: JSON string
    BulkHSMResponse:
      type: object
      properties:
        message:
          type: array
          items:
            type: string
        status:
          type: string
    CSVParam:
      type: object
      properties:
        param:
          type: integer
        column:
          type: string
    Error:
      type: object
      properties:
        message:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
        statusMessage:
          type: string
        status:
          type: integer
        error:
          type: object
          properties:
            code:
              type: string
            key:
              type: string
            description:
              type: string
            developerMessages:
              type: object
            clientMessages:
              type: object
        validationError:
          type: object
  responses:
    BadRequest:
      description: Bad request - Invalid format or missing required fields
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized - Invalid authentication credentials
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnprocessableEntity:
      description: Unprocessable entity - Validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: Basic authentication using Base64 encoded clientId:clientSecret

````