# WhatsApp Chat API

## Overview

QuickReply.ai offers a native AI builder (chatbot builder) that covers most use cases efficiently. For typical needs, this built-in tool provides an easy-to-use and effective solution. The WhatsApp Chat API should be used primarily for scenarios requiring a custom proprietary chatbot with specific functionalities that cannot be achieved with the native builder. This can also be used if you wish to integrate a Generative AI based chatbot on to WhatsApp channel over QuickReply.ai

***

## How It Works

* **Disable AI Builder (chatbot builder)**
  1. Firstly, you will need to disable the AI builder.
  2. To disable AI builder, you can delete all nodes from these playbooks - <mark style="color:green;">**`Default`**</mark>, <mark style="color:green;">**`Fallback`**</mark> and <mark style="color:green;">**`Transfer`**</mark><mark style="color:green;">.</mark> In each of the playbooks, add a <mark style="color:red;">**`End`**</mark> node at the start.
  3. Alternatively you can write to <help@quickreply.ai> get the AI Builder disabled.
* **Receiving Messages:**
  * Incoming messages from users are received through a webhook configured to handle these events.
* **Sending Messages:**
  * To send a message to a WhatsApp user, make a POST request to the Send Message endpoint with the required message details.
* **Handling Message Status Updates:**
  * Track the status of sent messages (e.g., delivered, read) via a webhook that provides real-time updates.

***

## API Endpoints

### <mark style="background-color:green;">Receive Message</mark>

To receive messages sent by users on your WhatsApp integrated with QuickReply.ai, you will need to configure a webhook url in your QuickReply.ai account.

<mark style="color:green;">`POST`</mark> `[Your Webhook URL]`

Webhook endpoint for receiving incoming messages from WhatsApp users.

**Headers**

| Field                                          | Value              |
| ---------------------------------------------- | ------------------ |
| Content-Type<mark style="color:red;">\*</mark> | `application/json` |

**Body**

<table><thead><tr><th width="199">Field</th><th width="173">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>id</code></td><td>string</td><td>Unique message id</td></tr><tr><td>phone</td><td>string</td><td>Phone no. in E164 Format starting + with country code and phone number without any space or other chars</td></tr><tr><td>reply_to</td><td>string</td><td>Id of the message replied to (if user replied to a particular message)</td></tr><tr><td>msg_time</td><td>number</td><td>Time in milli-seconds</td></tr><tr><td>payload</td><td>JSON Object</td><td><a href="#payload-object">Payload Object is explained below</a></td></tr><tr><td>messageBy</td><td>string</td><td>Fixed value <code>USER</code></td></tr><tr><td>name</td><td>string</td><td>Name of user set in QuickReply</td></tr><tr><td>email</td><td>string</td><td>Email of user if set in QuickReply</td></tr></tbody></table>

#### **Payload Object**

<table><thead><tr><th width="154">Field</th><th width="129">Type</th><th>Description</th></tr></thead><tbody><tr><td>_type</td><td>string</td><td>one of <mark style="color:red;"><code>USER_TEXT</code></mark> ,<mark style="color:red;"><code>USER_FILE</code></mark> ,<mark style="color:red;"><code>USER_LIST_REPLY</code></mark> or <mark style="color:red;"><code>USER_BUTTON_REPLY</code></mark></td></tr><tr><td>text</td><td>string</td><td>Text sent by user<br>(in case of <mark style="color:red;"><code>USER_TEXT</code></mark>)</td></tr><tr><td>name</td><td>string</td><td>Name of file<br>(in case of <mark style="color:red;"><code>USER_FILE</code></mark>)</td></tr><tr><td>contentType</td><td>string</td><td>Content type of file<br>(in case of <mark style="color:red;"><code>USER_FILE</code></mark>)</td></tr><tr><td>caption</td><td>string</td><td><p>Text sent by user</p><p>(in case of <mark style="color:red;"><code>USER_FILE</code></mark>)</p></td></tr><tr><td>status</td><td>string</td><td>"<mark style="color:green;">SUCCESS</mark>"</td></tr><tr><td>path</td><td>string</td><td><p>URL of the file</p><p>(in case of <mark style="color:red;"><code>USER_FILE</code></mark>)</p><p>This URL gets expired after an year, so it is recommended to download the file on your server</p></td></tr><tr><td>preview</td><td>JSON Object</td><td><p>Preview Object</p><p>(in case of reply message or message containing link)</p></td></tr></tbody></table>

#### **Preview Object**

<table><thead><tr><th width="149">Field</th><th width="111">Type</th><th>Description</th></tr></thead><tbody><tr><td>replyPreview</td><td>Object</td><td>Reply Preview Object<br>(When message is reply to another message)</td></tr><tr><td>urlPreview</td><td>Object</td><td>URL Preview Object<br>(When message contains URL)</td></tr></tbody></table>

{% hint style="info" %}
If a message has both reply to a message and a url, only the replyPreview will come.
{% endhint %}

#### Reply Preview Object

<table><thead><tr><th width="148">Field</th><th width="133">Type</th><th>Description</th></tr></thead><tbody><tr><td>header</td><td>Object</td><td><p><strong>Header Object Fields</strong></p><p><br>For replies to messages containing media such as videos, images, documents, or audio:</p><ol><li><strong>type</strong>: Specifies the type of header (e.g., image, video, document).</li><li><strong>previewImage</strong>: URL of the preview image, if available.</li></ol></td></tr><tr><td>body</td><td>Object</td><td><p><strong>Body Fields:</strong></p><ul><li><strong>text</strong>: Original text message to which this reply is given.</li></ul></td></tr><tr><td>meta</td><td>Object</td><td><p><strong>Metadata</strong></p><ul><li><strong>userId</strong>: The user ID assigned by QuickReply.ai.</li><li><strong>repliedMessageId</strong>: Internal message ID used by WhatsApp, typically not needed for user reference.</li></ul></td></tr></tbody></table>

\
**URL Preview Object**

<table><thead><tr><th width="145">Param</th><th width="132">Type</th><th>Description</th></tr></thead><tbody><tr><td>url</td><td>string</td><td>Complete URL for which preview is included</td></tr><tr><td>domain</td><td>string</td><td>domain of above URL</td></tr><tr><td>title</td><td>string</td><td>title shown to user in the preview</td></tr><tr><td>sitename</td><td>string</td><td>name of website (Currently not shown to user in WhatsApp)</td></tr><tr><td>description</td><td>string</td><td>description shown to user in the preview</td></tr><tr><td>image</td><td>Object</td><td><p><strong>Image Details</strong></p><ul><li><strong>url:</strong> <code>url of Image</code></li><li><strong>width:</strong> <code>width of Image</code></li><li><strong>Height:</strong> <code>height of Image</code></li></ul></td></tr></tbody></table>

#### Sample Payload objects

<details>

<summary>Text message sent by user</summary>

```json
{
  "id": "dq7HoK7y4yRMTEpj7_msg",
  "phone": "+9199XXXXXXXX1",
  "msg_time": 1725541364563,
  "payload": {
    "text": "HI",
    "_type": "USER_TEXT"
  }
}
```

</details>

<details>

<summary>Image message having a caption</summary>

```json
{
  "id": "HPXKPpoDpG6Ze3zbA_msg",
  "phone": "+919XXXXXXXX1",
  "msg_time": 1725543260528,
  "payload": {
    "_type": "USER_FILE",
    "path": "https://d2gxu7oczk95hf.cloudfront.net/company/XXXXXXX/chatusers/XXXXXXX/1725XXXXX543260344_original.jpeg?Expires=1757079260&Key-Pair-Id=APKAJJB3QB7QKGWPAGUQ&Signature=HiBVkaV6-kUBTq9zkpcUgGM3hF3rTuby3JQJgUDe55adCyiP~mX48RA2MYHYRrIGtpfb3am3XLNQilCRogwclU75Fg6citpzMGhtM0xrs7zdpRp0dNCgURjDF~6DOMk~dj50WMJWiZDKUBrha7gUaumAof~Pdc~oFCLBXhgHimuzisaCWcUtgXDxY3fC~9Q6hQdo5-6X2k6XdZDR6XHqlS01~zfcJZvABHjORVAa4DYve5YQxMpdTnVSg8iGiYpOybIoWd7nFqj2j~niZD-CESrCb87rNNu23TwNU4qVqzYTQF6C4LMJf9W1HFvZ8FKvo-VO46SBPEsOq6Qb~TZJ6g__",
    "name": "1725543260235",
    "status": "SUCCESS",
    "contentType": "image/jpeg",
    "audioText": "",
    "caption": "Team photo"
  } 
}
```

</details>

<details>

<summary>Image message without any caption</summary>

```json
{
  "id": "ZhzcpjQa3sgDkdM28_msg",
  "phone": "+919XXXXXXX1",
  "msg_time": 1725543296987,
  "payload": {
    "_type": "USER_FILE",
    "path": "https://d2gxu7oczk95hf.cloudfront.net/company/XXXXXXX/chatusers/XXXXXXX/172XXXXX6843_original.jpeg?Expires=1757079297&Key-Pair-Id=APKAJJB3QB7QKGWPAGUQ&Signature=EfZWoc1l6nRTDOusLzVfI4jJxmrT4COkbCJ7T0aMlUk4e4lPVQxoZ5Fn7NCQLwMieglyMnZ0OHzgKdKBK3a02Jqjc-jUgK3w4bMRtU6Wanm~hBVGaLyhf3caqdbKPguM66K0GEAyuEegXJbUb434LGP8DWq0yCSIWGaXIDA4OjlGdujPXJMc9t0qJfIF4v8VZgT2~Us5j~FdSuiU8mr0LgBtFuvxTLVnSy~3~NrSSiSW5luZAIeRSfWLq6wYGkkVZTJu4Hg9-qJiZ9122GIcgGzlqks1maI1UZi9sn2--cgMe-fDw2z-HLiFTQ-rSQB1qlH4C9z4ujwf-9-MgfXrXg__",
    "name": "1725543296811",
    "status": "SUCCESS",
    "contentType": "image/jpeg",
    "audioText": ""
  }
}
```

</details>

<details>

<summary>Document with caption</summary>

```json
{
  "id": "WX6Htqh4W6329JPX6_msg",
  "phone": "+919XXXXXXX1",
  "msg_time": 1725543340052,
  "payload": {
    "path": "https://d2gxu7oczk95hf.cloudfront.net/company/XXXXXX/chatusers/XXXXXX/1725543339425_original.pdf?Expires=1757079340&Key-Pair-Id=APKAJJB3QB7QKGWPAGUQ&Signature=WnZFt~bU4g56eFQsNC7mdyLf-BconFgWDYkA3BTP~pUDSdhvqRwBN7DEg-jvHUDJyRg6acB2moqnXmwKta2dtmQJXwShS~9XXTujCSLoH23VqEYz70ZUXBUKLo1i1byInjoKdYBT-QMQamzMzh9NJ0uEGRfD9MO1s119jSR7F~J11ppz2DDlro-lwe6Ci3CBG2j-~Sj6CSmk~ICf1eyp4eL7fsVaZZG2UK2tDA5XPF~Zt-h3b2YGhsXB-lMa1q4IZ8vYIwPxuTu5G~5oR7PKo3QbY2kAOu0QJhVZUXd7eUN-KGHUV-OUThlKtSg3M85YR-cIAkr1RlO9WsyJ4MulfA__",
    "_type": "USER_FILE",
    "name": "Documentation_QR_2024.pdf",
    "status": "SUCCESS",
    "contentType": "application/pdf",
    "audioText": "",
    "caption": "Documentation for QuickReply.ai platform"
  }
}
```

</details>

<details>

<summary>Video with caption</summary>

```json
{
  "id": "gC8LSjZEWyZgkDYLs_msg",
  "phone": "+919XXXXXXX1",
  "msg_time": 1725543511327,
  "payload": {
    "path": "https://d2gxu7oczk95hf.cloudfront.net/company/XXXXXXX/chatusers/XXXXXXX/1725XXXXX078_original.mp4?Expires=1757079511&Key-Pair-Id=APKAJJB3QB7QKGWPAGUQ&Signature=B9qyHaK4GJakJ8dcK2BJdE-9RdRJrZLfL5XofrQOpwdNwXtNvmca90juytlgbO-ZczqH6MeqEj5rUBw8K7i2-ZAR8TGpmoJz9LK5E5dHUyzmi863rdyM8LdcgsqkhaD0I6HUW5r1M3bxXHVVQ3082SCfel-ja4FWps~5KC0FgovONl5nWBQYfdsVf2A66Cz8jHjn0KywmMOV7hIQ7hABYBK18c3i80Bl5SOF2d4Gi1WblGBCXMCQVN1YtCGnm7qYKykdRUg1wmOFOylgp3WjO8Fq2Q0z-WVO1BM6RYnMPPqFGR0Pp5tOJJgYehsvBPxvVKU5aYaURONVlF80gLbbVg__",
    "_type": "USER_FILE",
    "name": "1725543511019",
    "status": "SUCCESS",
    "contentType": "video/mp4",
    "audioText": "",
    "caption": "Screen recording example"
  }
}
```

</details>

<details>

<summary>Reply to a text message with a text message</summary>

```json
{
  "id": "PNRNu5GjgcdJgiaK2_msg",
  "phone": "+919XXXXXXX1",
  "msg_time": 1725543565950,
  "reply_to": "WSvFqApKjeRcS3KBM_msg"
  "payload": {
    "text": "hello reply message",
    "_type": "USER_TEXT",
    "preview": {
      "replyPreview": {
        "body": {
          "text": "hi this is original message"
        },
        "meta": {
          "userId": "zvYeDsXJdpCW6fC2e_ag",
          "repliedMessageId": "wamid.HBgMOTE5OTIyNTY0MzExFQIAERgSNDI0N0MwRTk0MDQ1RURDRTY1AA=="
        }
      }
    }
  }
}
```

</details>

<details>

<summary>Reply to a text message with an Image having caption</summary>

```json
{
  "id": "FHc5F7coHPKyrtc6p_msg",
  "phone": "+919XXXXXXX1",
  "msg_time": 1725543650636,
  "reply_to": "ZdNfzpyzbyGRKarc8_msg"
  "payload": {
    "path": "https://d2gxu7oczk95hf.cloudfront.net/company/XXXXXXX/chatusers/XXXXXXX/1725543650523_original.jpeg?Expires=1757079650&Key-Pair-Id=APKAJJB3QB7QKGWPAGUQ&Signature=dCbDRQ8tn3gM3~ZZ0lDCIErFicsof5~1FS4~5v9-wfMmNWGX7qdHJXukMNCjbmy0JVtfEdxPQaToe5Vy7LBypytEsuKOGmtomkPEtJHp2MNLYQRZ8b3hiYj~wVcsRLGc7JePs4X-07MSQ9F8jb9CjIQ~x15ggw-usubV5UukOQOhJZXfFbkEuueltIzgsEgugN6bLmChnzeYihC2Gi9lPhbmmke-Wy6hU3AivV0T0N7LznnSm7gsa3bW4YnqNnRqcpAt4z3gQ9-bWyKikXAaVLpZ8ahpufDZEjHuN9ys9cHKnnWgim7NDNeMw6aTBTPg3-PHXlgZaTdtf1BNcEzp6w__",
    "_type": "USER_FILE",
    "name": "1725543650311",
    "status": "SUCCESS",
    "contentType": "image/jpeg",
    "audioText": "",
    "caption": "screenshot",
    "preview": {
      "replyPreview": {
        "body": {
          "text": "Hi this is original message"
        },
        "meta": {
          "userId": "zvYeDsXJdpCW6fC2e_ag",
          "repliedMessageId": "wamid.HBgMOTE5OTIyNTY0MzExFQIAERgSNjQ2N0Y1MDFDRkQxQUNFMjZGAA=="
        }
      }
    }
  }
}
```

</details>

<details>

<summary>Text message having a URL</summary>

```json
{
  "id": "MM9tmHwuXGbRiHHdj_msg",
  "phone": "+919XXXXXXX1",
  "msg_time": 1725545036650,
  "payload": {
    "text": "https://x.com/XDevelopers/status/1740386052446060725 check this tweet",
    "_type": "USER_TEXT",
    "preview": {
      "urlPreview": {
        "url": "https://x.com/XDevelopers/status/1740386052446060725",
        "domain": "x.com",
        "title": "Developers (@XDevelopers) on X",
        "sitename": "X (formerly Twitter)",
        "description": "Calling all #developers! 📣\n\nInnovate with our real-time and historical data on the X API.\n\nGet started with Pro👇",
        "image": {
          "url": "https://pbs.twimg.com/profile_images/1683501992314798080/xl1POYLw_200x200.jpg",
          "width": "80",
          "height": "80"
        }
      }
    }
  }
}
```

</details>

### <mark style="background-color:green;">Send Message</mark>

<mark style="color:green;">`POST`</mark> [`https://app.quickreply.ai/api/whatsapp/send-session-message`](https://app.quickreply.ai/api/whatsapp/send-session-message)

Sends a message to a specified WhatsApp user.

{% hint style="info" %}

* You can send message only if user has sent at least one message in the last 24 hours, otherwise message sending will fail.
* If you wish to initiate a conversation from your end, you should send Template Message with CTA buttons. If user replies, the session will start and you will be able to send messages.
  {% endhint %}

**Headers**

<table><thead><tr><th width="161">Field</th><th width="102">Type</th><th width="207">Value</th><th>Description</th></tr></thead><tbody><tr><td>client-id<mark style="color:red;">*</mark></td><td>string</td><td><code>&#x3C;client id></code></td><td>You can find client-id of your account in<br><code>Settings</code> > <code>Developers</code> > <code>API credentials</code></td></tr><tr><td>secret-key<mark style="color:red;">*</mark></td><td>string</td><td><code>&#x3C;secret key></code></td><td>You can find client-id of your account in<br><code>Settings</code> > <code>Developers</code> > <code>API credentials</code></td></tr><tr><td>Content-Type<mark style="color:red;">*</mark></td><td>string</td><td><code>application/json</code></td><td></td></tr></tbody></table>

**Body**

<table><thead><tr><th width="145">Param</th><th width="128">Type</th><th width="210">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>to</code><mark style="color:red;">*</mark></td><td>string</td><td><code>&#x3C;phone_number></code></td><td>Phone no. in E164 Format</td></tr><tr><td><code>payload</code><mark style="color:red;">*</mark></td><td>JSON object</td><td><code>&#x3C;payload object></code></td><td>Payload object is explained below</td></tr></tbody></table>

**Payload**

<table><thead><tr><th width="135">Field</th><th width="85">Type</th><th width="291">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>_type</code><mark style="color:red;">*</mark></td><td>string</td><td><code>AGENT_TEXT</code></td><td>Currently only text is supported. It doesn’t limit you from sending media using fields below</td></tr><tr><td><code>text</code></td><td>string</td><td><code>&#x3C;text to send></code></td><td>Message which is being sent to the user</td></tr><tr><td><code>img</code></td><td>url</td><td><code>URL of image</code></td><td>Image should be publicly accessible via URL. Max 5MB is allowed</td></tr><tr><td><code>video</code></td><td>url</td><td><code>URL of video</code></td><td>Video should be publicly accessible via URL. Max 16MB is allowed</td></tr><tr><td><code>audio</code></td><td>url</td><td><code>URL of audio</code></td><td>Audio should be publicly accessible via URL. Max 16MB is allowed</td></tr><tr><td><code>document</code></td><td>object</td><td><code>{</code><br><code>"link": "&#x3C;url>",</code><br><code>"filename":"&#x3C;filename>"</code><br><code>}</code></td><td><ol><li>url: Document should be publicly accessible via URL. Max 16MB is allowed</li><li>filename: Filename to be displayed in WhatsApp</li></ol></td></tr></tbody></table>

{% hint style="info" %}

* At a time, only one of the img, video, audio or document field can be supplied.
* Sending media is optional, and you can send only text as well.
  {% endhint %}

**Example**

```sh
curl --location 'https://app.quickreply.ai/api/whatsapp/send-session-message' \
--header 'client-id: <client-id>' \
--header 'secret-key: <client-secret>' \
--header 'Content-Type: application/json' \
--data '{
    "to": "+9196XX68XXXX",
    "payload" : {
        "text":"hi",
        "_type": "AGENT_TEXT"
    }
}'
```

**Response**

{% tabs %}
{% tab title="200" %}
Response is a JSON object with the following structure

<table><thead><tr><th width="124">Field</th><th width="76">Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>string</td><td>unique message id if message is sent. null if scheduled</td></tr><tr><td>state</td><td>string</td><td>One of the following<br>1. <mark style="color:red;"><code>SENT</code></mark> - When message is sent successfully.<br>2. <mark style="color:red;"><code>NOT_SENT</code></mark> - When an error occurs while sending message. at WhatsApp end<br>3. <mark style="color:red;"><code>SCHEDULED</code></mark> - When you call campaign API which schedules message to be sent in future instead of sending immediately.</td></tr><tr><td>reason</td><td>string</td><td>When message is not sent, Reason for <mark style="color:red;"><code>NOT_SENT</code></mark></td></tr></tbody></table>

**Example**

```json
{
    "id": "WSvFqApKjeRcS3KBM_msg",
    "state": "SENT"
}
```

{% endtab %}

{% tab title="400" %}
Response is a JSON object with the following structure

<table><thead><tr><th width="123">Param</th><th>Type</th><th>Value</th></tr></thead><tbody><tr><td>error</td><td>string</td><td>error message</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### <mark style="background-color:green;">Message Status Update</mark>

To receive messages delivery reports you will need to configure a webhook url in your QuickReply.ai account.

<mark style="color:green;">`POST`</mark> `[Your Webhook URL]`

Webhook endpoint for receiving message status updates from WhatsApp users.

\
**Body**

<table><thead><tr><th width="133">Field</th><th width="117">Type</th><th>Description</th></tr></thead><tbody><tr><td>id</td><td>string</td><td>unique message id</td></tr><tr><td>event</td><td>string</td><td>one of <mark style="color:red;"><code>SENT</code></mark> <mark style="color:red;"><code>DELIVERED</code></mark> <mark style="color:red;"><code>READ</code></mark></td></tr><tr><td>phone</td><td>string</td><td>Phone no. in E164 Format starting + with country code and phone number without any space or other chars</td></tr><tr><td>name</td><td>string</td><td>Name of user set in QuickReply</td></tr><tr><td>email</td><td>string</td><td>Email of user if set in QuickReply</td></tr><tr><td>messageBy</td><td>string</td><td>one of <code>AUTOMATION</code> or <code>AGENT</code></td></tr><tr><td>agentId</td><td>string</td><td>When messageBy is AGENT, it contains agent who sent message</td></tr><tr><td>automationBy</td><td>string</td><td>When messageBy is AUTOMATION, it contains what automation triggered this message. It will be one of <code>BROADCAST</code> <code>CAMPAIGN</code> <code>JOURNEY</code> <code>API_TEMPLATE</code> <code>CHAT_BOT</code></td></tr><tr><td>broadcastId</td><td>string</td><td>if automationBy is <code>BROADCAST</code> it contains broadcast id</td></tr><tr><td>campaignId</td><td>string</td><td>if automationBy is <code>CAMPAIGN</code> it contains campaign id</td></tr><tr><td>journeyId</td><td>string</td><td>if automationBy is <code>JOURNEY</code> it contains journey id</td></tr><tr><td>templateId</td><td>string</td><td>if it is template message, it contains template id</td></tr></tbody></table>

***

## Important Notes

* If you want your system to generate responses to incoming messages, you can ignore message events for messages not sent by you via API.
* If you are using GenAI/LLM to generate responses, you might need message history that you have to maintain on your own.

## How to Configure Webhooks?

To configure Webhooks, Send the URL you would like to configure to <help@quickreply.ai> and our support team will assist you.
