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

# Scheduled Messages

> How to schedule WhatsApp messages for a future date and time with the Zapster API using the send_at field. No cron jobs, queues, or timers on your side.

## What scheduled messages are

Scheduled messages let you send a message through the API today while it is only delivered to the recipient at a date and time you choose. Just include the `send_at` field in the send request and Zapster handles the rest.

This works for any message type: text, media (image, audio, video, document), templates, and messages with buttons. You do not need to build cron jobs, queues, or timers in your system. Zapster stores the message and guarantees the send at the right time.

In practice, it is like scheduling a message inside WhatsApp, except through the API and with full control over what happens at each step.

## Use cases

* **Payment reminders**: schedule a charge for the invoice due date.
* **Sales follow-ups**: send a message 2 days after the first contact with a lead.
* **Time-boxed campaigns**: prepare everything on Monday and spread the sends across the week.
* **Appointment confirmations**: remind the patient 1 day before the appointment.
* **Customer onboarding**: send usage tips in the first days after sign-up.
* **Satisfaction surveys**: trigger an NPS a few days after a purchase or support interaction.

## How it works

The flow is straightforward:

1. You send a `POST /v1/wa/messages` with the `send_at` field set to the desired date and time.
2. Zapster stores the message and creates an internal schedule.
3. At the defined time, the message is sent automatically by the configured instance.

If the send fails (instance offline, blocked number, network issue), the system retries up to 3 times. If all of them fail, the message status goes to `failed` and the `errors` field carries the details of the problem.

## Message lifecycle

Every scheduled message goes through the following states:

| From        | To          | When it happens                                           |
| ----------- | ----------- | --------------------------------------------------------- |
| (none)      | `scheduled` | Message created through the API with `send_at`            |
| `scheduled` | `sent`      | Sent successfully at the scheduled time                   |
| `scheduled` | `failed`    | Send failed after 3 attempts                              |
| `scheduled` | `canceled`  | Canceled by the user through `DELETE /v1/wa/messages/:id` |

<Note>
  Once the message reaches the `sent` status, the system also records the `delivered_at` (delivery confirmed on the device) and `read_at` (recipient read the message) timestamps. But the status stays `sent`: delivery and read are tracked only through timestamps.
</Note>

## Limits per plan

|                      | Essential | Pro     | Enterprise |
| -------------------- | --------- | ------- | ---------- |
| Concurrent scheduled | 10        | 500     | 10,000     |
| Maximum lead time    | 7 days    | 1 year  | No limit   |
| History retention    | 24 hours  | 30 days | 180 days   |

Explaining each row:

* **Concurrent scheduled**: the number of messages with `scheduled` status that can exist at the same time in your account. If you have 10 pending messages on the Essential plan, you need to wait for one to be sent (or cancel one) before scheduling another.
* **Maximum lead time**: how far into the future you can schedule. On Essential, up to 7 days. On Pro, up to 1 year.
* **History retention**: how long you can query already-sent messages. On Essential, only the last 24 hours are available for lookup.

## Compatibility

It works with both official (WABA) and unofficial (QR code) instances. You do not need to change anything in your instance configuration to use scheduling.

## About time zones

The `send_at` field accepts dates in the ISO 8601 format, which includes time zone information. In practice, you have two options:

* Send with an explicit time zone: `"2026-03-30T09:00:00-03:00"` (Brasília time).
* Send in UTC: `"2026-03-30T12:00:00Z"`.

Both examples above represent the same moment. The only difference is how you write it.

The API response always returns dates in UTC, regardless of the time zone you used when sending.

<Tip>
  If you do not want to do time zone math, send the date in your local time with the offset at the end. For example, `"2026-03-30T09:00:00-03:00"` sends at 9 AM Brasília time.
</Tip>
