## Send notification

`POST https://whatsapp.paaltech.org/api/v1/businesses/{external_id}/notifications`

One notification, tried on `channels` in order (default whatsapp, sms, email) until one
takes it. A channel is passed over when there is no content or address for it, the
business has not set it up, its provider is unavailable, or the send is refused (opted
out, suppressed...). If its message later fails, the next channel is tried. A message
whose fate is unknown never triggers the next channel - it may already have arrived.
Addresses come from `to`, or from the contact (`contact_id`). Same `reference`, same
notification.

Ability: `messages.send`

### Path parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `external_id` | string | yes | Your own ID for the business (Multi-SKUUL - the tenant ID). Max 191 characters. Pattern `^[A-Za-z0-9._:-]+$` |

### Body

| Name | Type | Required | Description |
|---|---|---|---|
| `channels` | array of strings | no |  |
| `contact_id` | integer | null | no |  |
| `to` | object | null | no |  |
| `to.whatsapp` | string | no |  |
| `to.sms` | string | no |  |
| `to.email` | string | no |  |
| `whatsapp` | object | null | no |  |
| `whatsapp.template` | object | no | Name, language and components - as on Send message. |
| `sms` | object | null | no |  |
| `sms.text` | string | no | Max 918 characters |
| `email` | object | null | no |  |
| `email.subject` | string | no |  |
| `email.text` | string | no |  |
| `reference` | string | null | no | Max 150 characters |
| `category` | string | null | no | One of: `marketing`, `notifications`, `transactional`, `` |
| `topic` | string | null | no |  |
| `urgent` | boolean | no |  |

### Request

```bash
curl --request POST \
  --url 'https://whatsapp.paaltech.org/api/v1/businesses/presec/notifications' \
  --header "Authorization: Bearer $PAALCHAT_TOKEN" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
  "contact_id": 41,
  "reference": "closing-2026-10-02",
  "whatsapp": {"template": {"name": "school_closing", "language": "en_US"}},
  "sms": {"text": "Presec: school closes at 1pm today."},
  "email": {"subject": "School closes early", "text": "School closes at 1pm today."}
}'
```

### Responses

- **200** - Duplicate reference - the original notification.
- **202** - Accepted; on its first usable channel.
- **401** - unauthenticated - missing, invalid, revoked or expired token

```json
{
  "error": {"code": "unauthenticated", "message": "A valid product token is required."}
}
```

- **403** - missing_ability, product_suspended or product_token_required

```json
{
  "error": {
    "code": "missing_ability",
    "message": "This token does not have the ability this request needs."
  }
}
```

- **404** - not_found - not yours, or does not exist

```json
{"error": {"code": "not_found", "message": "Business not found."}}
```

- **422** - validation_failed - fields are invalid; see errors.

```json
{
  "error": {
    "code": "validation_failed",
    "message": "The external id field format is invalid. (and 1 more error)"
  },
  "errors": {
    "external_id": ["The external id field format is invalid."],
    "name": ["The name field is required."]
  }
}
```

- **429** - rate_limited - over 300 requests/minute for this product

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and retry after the Retry-After header."
  }
}
```

