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

# Individual Send (1-1)

> Send personalized HSM messages to individual recipients using the WhatsApp API

The WhatsApp API allows companies to automate and personalize communication with their customers, enabling efficient, scalable interactions enriched with multimedia content. It is ideal for managing inquiries, sending notifications, and providing immediate responses through AI Agents.

***

## Message sending configuration

### Step 1: Define the Endpoint

To send messages, use the following API endpoint:

```
POST https://api.jelou.ai/v2/whatsapp/{botId}/hsm
```

### Step 2: Request Parameters

The key parameters for the request include:

* **Text**: The message content.
* **Message type (`type`)**: Defines the type of template to be sent.
* **Template property**: Template previously created and approved by META.
* **Media file**: If the template requires a URL (image, document, etc.).
* **Bot ID**: Unique bot identifier.
* **Parameters**: Specific data for each send (name, order number, etc.).

### Step 3: Send the request

Send the message using the **POST** method. Upon completing the send, you will receive a response that allows you to verify the delivery status.

<Tip>
  Make sure to comply with WhatsApp policies to avoid restrictions.
</Tip>

***

## Content restrictions

Remember that, to send messages through WhatsApp, you must use templates previously approved by META.

Each template has specific limitations based on its format and content, such as message length or the type of information allowed. Make sure to review these restrictions before using them to ensure correct delivery.

**Keep in mind that**:

* URLs, emojis, and multimedia files are not allowed within authentication messages.
* Parameters must have a maximum of 15 characters.

***

## Request Body

| Property             | Type   | Description                                                                                           | Required    |
| -------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ----------- |
| **mediaUrl**         | string | Public URL of the media file. Required if your template is of type video, image, or document.         | Conditional |
| **filename**         | string | File name for document-type templates.                                                                | Conditional |
| **type**             | string | Message type: `text`, `hsm`, `image`, `document`, `video`, `catalog`, `carousel`. Defaults to `text`. | No          |
| **language**         | string | Template language: `en`, `es`, `pt`                                                                   | No          |
| **elementName**      | string | Name of the approved template.                                                                        | Yes         |
| **parameters**       | array  | Set of strings that replace values in the template.                                                   | Yes         |
| **destinations**     | array  | List of phone numbers. Numeric format with country code, without `+` or spaces.                       | Yes         |
| **buttonPayloads**   | array  | Information for quick reply buttons.                                                                  | No          |
| **actions**          | object | Template configuration and actions in payload format.                                                 | No          |
| **headerParameters** | array  | Header parameter, maximum 1 parameter.                                                                | No          |
| **thumbnailProduct** | string | Thumbnail image URL. Required for catalog templates.                                                  | Conditional |
| **expirationTime**   | string | Expiration time in timestamp format (milliseconds).                                                   | No          |
| **campaignId**       | string | Unique identifier of the associated campaign.                                                         | No          |
| **buttonParameters** | array  | Configuration for all button types.                                                                   | No          |
| **ltoParams**        | object | Limited time offer (LTO) parameters.                                                                  | No          |
| **cards**            | array  | Content cards for carousel templates.                                                                 | No          |

***

## Template types

In this section, we share request examples for the different template types. These examples provide a clear guide so you can easily substitute the values with your own data.

<Warning>
  If a template name or a button within the JSON differs from the already approved template, even by an accent mark, the send will fail. **Precision is key to ensuring functionality.**
</Warning>

<AccordionGroup>
  <Accordion title="Text message">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "parameters": ["PARAMETER_1", "PARAMETER_2"],
        "destinations": ["PHONE_NUMBER"],
        "elementName": "ELEMENT_NAME"
      }'
    ```
  </Accordion>

  <Accordion title="Message with image">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "parameters": ["PARAMETER_1", "PARAMETER_2"],
        "mediaUrl": "https://cdn.example.com/image.jpeg",
        "type": "image",
        "destinations": ["PHONE_NUMBER"],
        "elementName": "ELEMENT_NAME"
      }'
    ```
  </Accordion>

  <Accordion title="Message with video">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "parameters": ["PARAMETER_1", "PARAMETER_2"],
        "mediaUrl": "https://cdn.example.com/video.mp4",
        "type": "video",
        "destinations": ["PHONE_NUMBER"],
        "elementName": "ELEMENT_NAME"
      }'
    ```
  </Accordion>

  <Accordion title="Message with attached document">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "parameters": ["PARAMETER_1"],
        "mediaUrl": "https://cdn.example.com/document.pdf",
        "type": "document",
        "destinations": ["PHONE_NUMBER"],
        "elementName": "ELEMENT_NAME"
      }'
    ```
  </Accordion>

  <Accordion title="Text message with static URL action buttons">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "parameters": ["PARAMETER_1"],
        "destinations": ["PHONE_NUMBER"],
        "elementName": "ELEMENT_NAME"
      }'
    ```
  </Accordion>

  <Accordion title="Text message with dynamic URL action buttons">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Accept-Language: en' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "destinations": ["PHONE_NUMBER"],
        "parameters": ["PARAMETER_1"],
        "elementName": "ELEMENT_NAME",
        "buttonParameters": [
          {
            "type": "URL",
            "payload": {"param": "PARAM_URL"}
          }
        ]
      }'
    ```
  </Accordion>

  <Accordion title="Text message with Quick Reply buttons">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "elementName": "ELEMENT_NAME",
        "language": "en",
        "type": "text",
        "parameters": ["param1", "param2"],
        "destinations": ["PHONE_NUMBER"],
        "buttonParameters": [
          {
            "type": "QUICK_REPLY",
            "payload": {"type": "edge", "action": "BTN1", "skillId": "1"}
          },
          {
            "type": "QUICK_REPLY",
            "payload": {"type": "edge", "action": "BTN2", "skillId": "2"}
          },
          {
            "type": "QUICK_REPLY",
            "payload": {"type": "edge", "action": "BTN3", "skillId": "3"}
          }
        ]
      }'
    ```
  </Accordion>

  <Accordion title="Personalized text message with header parameters">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "elementName": "ELEMENT_NAME",
        "destinations": ["PHONE_NUMBER"],
        "parameters": ["PARAMETER_1", "PARAMETER_2"],
        "headerParameters": ["PARAMETER_VALUE"]
      }'
    ```
  </Accordion>

  <Accordion title="Full catalog">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "elementName": "ELEMENT_NAME",
        "destinations": ["PHONE_NUMBER"],
        "parameters": ["PARAMETER_1"],
        "type": "catalog",
        "buttonParameters": [
          {
            "type": "CATALOG",
            "payload": {"thumbnailProduct": "productId"}
          }
        ]
      }'
    ```
  </Accordion>

  <Accordion title="LTO with copy code button">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "buttonOptions": {},
        "elementName": "ELEMENT_NAME",
        "destinations": ["PHONE_NUMBER"],
        "parameters": ["PARAMETER_1", "PARAMETER_2"],
        "type": "image",
        "mediaUrl": "https://cdn.example.com/image.jpeg",
        "ltoParams": {"expirationTime": 1733260800000},
        "buttonParameters": [
          {
            "type": "COPY_CODE",
            "param": 1,
            "payload": {"param": "20OFF"}
          }
        ]
      }'
    ```
  </Accordion>

  <Accordion title="Authentication">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "buttonOptions": {},
        "elementName": "ELEMENT_NAME",
        "destinations": ["PHONE_NUMBER"],
        "parameters": ["PARAMETER_1"],
        "type": "hsm"
      }'
    ```
  </Accordion>

  <Accordion title="Carousel with 2 cards">
    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "elementName": "ELEMENT_NAME",
        "destinations": ["PHONE_NUMBER"],
        "parameters": [],
        "type": "carousel",
        "cards": [
          {
            "mediaUrl": "https://cdn.example.com/product1.jpg",
            "params": ["PARAMETER_VALUE"],
            "buttonParameters": [
              {
                "type": "QUICK_REPLY",
                "payload": {"action": "Button 1", "type": "edge", "skillId": "45515", "cardIndex": 0}
              }
            ]
          },
          {
            "mediaUrl": "https://cdn.example.com/product2.jpg",
            "params": ["PARAMETER_VALUE_1", "PARAMETER_VALUE_2"],
            "buttonParameters": [
              {
                "type": "QUICK_REPLY",
                "payload": {"action": "Button 2", "type": "edge", "skillId": "10192", "cardIndex": 1}
              }
            ]
          }
        ]
      }'
    ```
  </Accordion>
</AccordionGroup>

***

## Common use cases

### 1. Personalized messages

Use templates with variables to send messages tailored to each user's needs (for example, payment reminders or order updates).

### 2. Automation with Webhooks

Personalized interactions based on user responses, allowing for a more dynamic and efficient conversation.

**Campaign examples**:

* **Personalized promotions**: Exclusive offers based on customer preferences.
* **Payment reminders**: Automatic notifications for invoice due dates.
* **Service quotes**: Quick inquiries about insurance, loans, etc.

***

## Advanced configuration

### Phone number

Since this is an individual send, the phone number of the recipient must be in the correct format for the send to be successful.

The `+` sign must be omitted, the country code must be included, and only numeric characters are allowed. Dashes or spaces are not accepted.

<Warning>
  **For users in Ecuador:** The "+" sign and the first 0 of the phone number must be omitted for it to be entered correctly.
</Warning>

| ✅ Correct format | ❌ Incorrect format | ❌ Incorrect format |
| :--------------: | :----------------: | :----------------: |
|   PHONE\_NUMBER  |   +PHONE\_NUMBER   |     09XXXXXXXX     |

### Specific parameters

Depending on the campaign, you can use personalized data such as the message type or additional customer information.

***

## Message personalization

### Linking with Workflows

Each message can be associated with a specific workflow that defines how the user's response should be handled. This is useful for creating more complex and targeted interactions, such as interactive menus or surveys.

### Button configuration

<Accordion title="Button Payload">
  You can use the following structure in the `buttonPayloads` field when your template includes quick reply buttons using workflows; this will allow you to activate additional flows within the conversation based on the action selected by the user.

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

  In this case, each button must have the keys `type`, `action`, and `skillId`. The `action` key defines the text that will appear on the button, while `skillId` indicates the ID of the workflow that the button will activate.

  <Tip>
    To get the `skillId` of a workflow, hover over the workflow name in Brain Studio. A tooltip will appear showing the corresponding ID.
  </Tip>
</Accordion>

<Accordion title="Actions Payload">
  Redirect users to specific workflows based on their choice or interaction.

  Templates allow the following configurations:

  ```json theme={null}
  {
    "actions": {
      "setSkill": {"id": 2222}
    }
  }
  ```

  <Tip>
    To get the `skillId` of the workflow, hover over the workflow name in Brain Studio. A tooltip will appear showing the corresponding ID.
  </Tip>

  ```json theme={null}
  {
    "actions": {
      "setMemoryParams": {
        "url": "https://apps.jelou.ai"
      }
    }
  }
  ```
</Accordion>

### Cache Parameters

This function is used to save additional information in the cache for later use. It will depend on the desired configuration for the template. If a URL is sent, it can be used by a workflow to redirect that URL for marketing purposes.

All parameters to be stored in cache must go in `setMemoryParams` with their respective key-value fields.

<Note>
  This configuration will be valid for 3 months.
</Note>

```json theme={null}
{
  "actions": {
    "setMemoryParams": {
      "url": "https://apps.jelou.ai"
    }
  }
}
```

***

## API Responses

<AccordionGroup>
  <Accordion title="200 - Successful response">
    ```json theme={null}
    [
      {
        "id": "msg-12345-67890-abcde-fghij-klmno",
        "destination": "PHONE_NUMBER"
      }
    ]
    ```
  </Accordion>

  <Accordion title="400 - Bad Request">
    ```json theme={null}
    {
      "message": ["Template does not exist"],
      "status": "failed",
      "_metadata": {
        "error": {},
        "body": {
          "destinations": [{"destination": "PHONE_NUMBER"}],
          "parameters": ["John", "example_value"],
          "elementName": "sample_template",
          "code": "en",
          "type": "text",
          "botId": "BOT_ID",
          "botName": "Your Bot"
        }
      },
      "error": {}
    }
    ```
  </Accordion>

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

  <Accordion title="404 - Not Found">
    ```json theme={null}
    {
      "message": ["The Bot could not be found at the moment."],
      "statusMessage": "failed",
      "status": 0,
      "error": {
        "code": "E1019",
        "key": "BOT_NOT_FOUND",
        "description": "Error to be thrown when trying to get a Bot.",
        "developerMessages": {
          "es": "El botId no se encuentra en la base de datos o ha sido eliminado.",
          "en": "The botId is not found in the database or has been deleted."
        },
        "clientMessages": {
          "es": "El Bot no se pudo encontrar por el momento.",
          "en": "The Bot could not be found at the moment."
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="422 - Unprocessable Entity">
    ```json theme={null}
    {
      "message": ["The values entered are not correct."],
      "statusMessage": "failed",
      "status": 0,
      "error": {
        "code": "E0422",
        "key": "VALIDATOR_ERROR",
        "description": "Error to be thrown when cannot process request because of incoming values",
        "developerMessages": {
          "es": "Los valores del request no son correctos para ser procesados.",
          "en": "The request values are not correct for processing."
        },
        "clientMessages": {
          "es": "Los valores ingresados no son correctos.",
          "en": "The values entered are not correct."
        }
      },
      "validationError": {
        "parameters": [
          {
            "en": "The number of parameters is incorrect.",
            "es": "El número de parámetros es incorrecto."
          }
        ]
      }
    }
    ```
  </Accordion>

  <Accordion title="500 - Internal Server Error">
    ```json theme={null}
    {
      "message": ["We are having trouble processing your request. Please try again later."],
      "statusMessage": "failed",
      "status": 0,
      "error": {
        "code": "E0000",
        "key": "UNKNOWN_ERROR",
        "description": "Error to be thrown when it couldn't be determined the reason of failure",
        "developerMessages": {
          "es": "Error inesperado occurido, revisar logs.",
          "en": "Unexpected error occurred, check logs."
        },
        "clientMessages": {
          "es": "Estamos teniendo problemas procesando la solicitud. Por favor intenta mas tarde.",
          "en": "We are having trouble processing your request. Please try again later."
        }
      }
    }
    ```
  </Accordion>
</AccordionGroup>

***

## Recommended tools for testing

To facilitate testing and sending requests, we recommend using tools such as:

* **Postman**
* **Insomnia**

These tools allow you to make HTTP requests easily, test different configurations, and review API responses.

***

## Frequently asked questions

<AccordionGroup>
  <Accordion title="How many characters are allowed?">
    There is currently no defined character limit per message; however, you should be mindful of the size of files that are part of the message, such as: image, video, or document. These are shared via mediaUrl.

    At Jelou, we have the following size and format limitations to follow:

    * **DOCUMENT:** Up to 15MB - Format: `.pdf`
    * **VIDEO:** Up to 15MB - Format: `.mp4`
    * **IMAGE:** Up to 5MB - Formats: `.jpg`, `.jpeg`, `.png`
  </Accordion>

  <Accordion title="How is the API consumed?">
    Both the bulk and 1-1 send cURLs can be consumed in any HTTPS client such as Insomnia or Postman. Simply create an HTTPS request using the cURL (just paste it), then change the data and execute.

    Here is an example with basic-auth:

    ```bash theme={null}
    curl --request POST \
      --url 'https://api.jelou.ai/v2/whatsapp/BOT_ID/hsm' \
      --header 'Accept-Language: en' \
      --header 'Authorization: Basic {{Base64EncodedUsername:Password}}' \
      --header 'Content-Type: application/json' \
      --data '{
        "destinations": ["PHONE_NUMBER"],
        "parameters": [],
        "elementName": "your_template_name"
      }'
    ```
  </Accordion>
</AccordionGroup>


## OpenAPI

````yaml POST /v2/whatsapp/{botId}/hsm
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:
  /v2/whatsapp/{botId}/hsm:
    post:
      tags:
        - Campaigns
      summary: Send Individual HSM
      description: >-
        Send a WhatsApp HSM template message to one or more recipients. Supports
        text, image, video, document, catalog, and carousel templates.
      operationId: sendIndividualHSM
      parameters:
        - name: botId
          in: path
          required: true
          description: The unique identifier of the bot
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HSMRequest'
      responses:
        '200':
          description: HSM sent successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HSMResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
components:
  schemas:
    HSMRequest:
      type: object
      required:
        - elementName
        - destinations
      properties:
        mediaUrl:
          type: string
          format: uri
          description: Public URL for media (required for image/video/document templates)
        filename:
          type: string
          description: Filename for document templates
        type:
          type: string
          enum:
            - text
            - hsm
            - image
            - document
            - video
            - catalog
            - carousel
          default: text
        language:
          type: string
          enum:
            - en
            - es
            - pt
        elementName:
          type: string
          description: Approved template name
        parameters:
          type: array
          items:
            type: string
          description: Template parameter values
        destinations:
          type: array
          items:
            type: string
          description: Phone numbers with country code, no + sign
        buttonPayloads:
          type: array
          items:
            type: object
        actions:
          type: object
        headerParameters:
          type: array
          items:
            type: string
          maxItems: 1
        buttonParameters:
          type: array
          items:
            $ref: '#/components/schemas/ButtonParameter'
        ltoParams:
          $ref: '#/components/schemas/LTOParams'
        cards:
          type: array
          items:
            $ref: '#/components/schemas/CarouselCard'
        expirationTime:
          type: string
          description: Expiration timestamp in milliseconds
        campaignId:
          type: string
    HSMResponse:
      type: array
      items:
        type: object
        properties:
          id:
            type: string
          destination:
            type: string
    ButtonParameter:
      type: object
      properties:
        type:
          type: string
          enum:
            - URL
            - QUICK_REPLY
            - CATALOG
            - COPY_CODE
        payload:
          type: object
        param:
          type: integer
    LTOParams:
      type: object
      properties:
        expirationTime:
          type: integer
          description: Expiration timestamp in milliseconds
    CarouselCard:
      type: object
      properties:
        mediaUrl:
          type: string
          format: uri
        params:
          type: array
          items:
            type: string
        buttonParameters:
          type: array
          items:
            $ref: '#/components/schemas/ButtonParameter'
    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'
    NotFound:
      description: Not found - Resource not found
      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

````