> For the complete documentation index, see [llms.txt](https://docs.channel360.co.za/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.channel360.co.za/api-usage/reply-to-a-customer.md).

# Reply to a customer

Answer a customer who messaged you with text, media, buttons or lists, within 24 hours.

When a customer writes to you, you can answer with free-form messages — text, images, files, buttons, lists — for 24 hours.

{% hint style="info" %}
**The 24-hour rule.** You can only reply after the customer has messaged you, and only within 24 hours of their **latest** message. Outside that window, send a [template notification](/api-usage/send-a-template-notification.md) instead. When the customer answers it, the window opens again.
{% endhint %}

## Before you start

* A webhook that receives the `message:appUser` event — see [Receive delivery updates](/api-usage/receive-delivery-updates.md).
* An API key and your Organisation API URL — see [Authentication](/api-usage/get-started/authentication.md).

## Steps

### 1. Receive the customer's message

When the customer writes to you, your webhook receives a `message:appUser` event.

### 2. Read the app user ID

Take `appUser._id` from that event. This is Channel360's ID for the customer, and it is where the reply is sent. In the examples below it is `<APP_USER_ID>`.

### 3. Send the reply

`POST` `/org/<ORG_ID>/whatsapp/appuser/<APP_USER_ID>/reply`

```
https://channel360.co.za/v1.1/org/<ORG_ID>/whatsapp/appuser/<APP_USER_ID>/reply
```

Headers:

```
Authorization: Bearer <API_KEY>
Content-Type: application/json
```

The `type` field picks the kind of message. Leave it out for text.

| `type`             | Also send                               | Result                              | Page                                                                                     |
| ------------------ | --------------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------- |
| *(none)* or `text` | `text`                                  | A text message                      | [Send a text reply](/api-usage/reply-to-a-customer/send-a-text-reply.md)                 |
| `image`            | `mediaUrl`, optional `text` (caption)   | An image                            | [Send a media reply](/api-usage/reply-to-a-customer/send-a-media-reply.md)               |
| `video`            | `mediaUrl`, optional `text`, `filename` | A video                             | [Send a media reply](/api-usage/reply-to-a-customer/send-a-media-reply.md)               |
| `audio`            | `mediaUrl`, optional `filename`         | An audio clip                       | [Send a media reply](/api-usage/reply-to-a-customer/send-a-media-reply.md)               |
| `document`         | `mediaUrl`, optional `filename`, `text` | A downloadable file                 | [Send a media reply](/api-usage/reply-to-a-customer/send-a-media-reply.md)               |
| `interactive`      | `interactive` (object)                  | A list, buttons, or a WhatsApp Flow | [Send an interactive reply](/api-usage/reply-to-a-customer/send-an-interactive-reply.md) |

`file` also exists for older integrations. Use `document` instead.

## Check it worked

* The API returns `201` with `{ "messages": [ { … } ] }`, containing the message that was sent.
* Your webhook receives `message:delivery:channel`, then `message:delivery:user`. Replies use these `message:*` events, not the `notification:*` ones.

## What can go wrong

| What you see                                               | Why                                                                                              | What to do                                                                           |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| **400** `A customer must reply to the conversation first.` | This customer has never messaged you.                                                            | Send a template notification instead.                                                |
| **400** `The 24-hour chat window has expired`              | Their last message is more than 24 hours old.                                                    | Send a template notification, and reply when they answer.                            |
| **400** about an unsupported type                          | `type` is not one of the values above.                                                           | Use a value from the table.                                                          |
| **400** with a WhatsApp error message and code             | WhatsApp rejected the message, for example a bad media link or a malformed `interactive` object. | Read the message. Check the link is public and the object matches WhatsApp's format. |
| **429** `Rate limit hit (meta code …)`                     | WhatsApp is limiting how fast your number can send. Nothing was sent.                            | Wait, then send again. There is no `Retry-After` header.                             |
| **401 / 403**                                              | Wrong API key or organisation.                                                                   | See [Authentication](/api-usage/get-started/authentication.md).                      |

A **400** saying an integration is "not set up" means WhatsApp is not connected for your organisation. Contact Channel360 support.

## Next

{% content-ref url="/pages/fTEWK9N7nzgvZk5vRc7V" %}
[Send a text reply](/api-usage/reply-to-a-customer/send-a-text-reply.md)
{% endcontent-ref %}

{% content-ref url="/pages/MMPfEfAxW2dosIuGBfym" %}
[Match replies to your records](/api-usage/match-replies-to-your-records.md)
{% endcontent-ref %}
