Skip to main content
One endpoint sends everything: POST /v1/messages. The type field decides the shape of the rest of the body. It defaults to text.

The 24-hour window

This governs everything else on this page.

Window open

The contact messaged you within the last 24 hours. Send anything — free-form text, media, interactive.

Window closed

Only an approved template will go out. Free-form sends are refused.
LazyApp enforces this server-side. A free-form send outside the window fails with a clear error instead of quietly disappearing. Replies inside the window are service messages. They are not unlimited and free: from 1 October 2026 Meta gives each number 1,000 free service messages a month and charges for the rest, billed to your own Meta payment method. See Service messages from 1 October 2026.

Addressing a recipient

By phone number, in E.164:
Or by business-scoped user id, when Meta gave you one instead of a number:
Or to a WhatsApp group you run, with "type": "group_id" (see Group chats). Contacts who adopt a WhatsApp username may only have a BSUID; see Identity, privacy and data.

Types

Up to 4096 characters.

Replying to a specific message

Quote the message you are answering, so it threads in the recipient’s client:

Service window

Free-form messages only land within 24 hours of the contact’s last inbound message. Outside that window, send a template. GET /v1/contacts/{contact} includes service_window so you can choose the right message type before sending:
state is open, expiring (less than two hours left) or closed. If you send anyway and the window is closed, the refusal carries code: customer_service_window_closed. See Errors.

Scheduling

Add send_at and the response becomes 202 with a scheduled id instead of a sent message:
ttl_seconds drops the message if it could not be sent within that window — better than a reminder arriving six hours late. List with GET /v1/messages/scheduled and cancel with DELETE.

How send_at is interpreted

There is no separate timezone field. The instant is taken from the string you send: These three schedule the same instant (09:00 India Standard Time):
The classic bug is a naive local time with no offset — it is treated as UTC, so the message goes out hours early or late for Indian and other non-UTC businesses. Prefer an explicit offset or Z. Responses return send_at as ISO 8601. Convert to the viewer’s timezone at display time; do not assume it comes back in the offset you sent. LazyApp does not offer profile “queues” that drip-feed posts into recurring slots. For a batch of reminders, compute each send_at yourself (or stagger in your worker) and create one scheduled message per send. Statuses and webhooks for scheduled vs sent messages are covered in Message lifecycle.

Confirming a send

Fetch any message by uuid with GET /v1/messages/{uuid}. Prefer webhooks in production; the GET is for confirmation and debugging.

Metadata

Attach up to 20 string values. They come back on webhooks, which makes reconciliation easy without a lookup table:

Direct send

Numbers enrolled in Meta’s direct-send programme can send utility and authentication content without a pre-approved template, via POST /v1/messages/direct-send. Marketing is not eligible. Check capabilities before relying on it. See Direct Send for buttons, media headers and business-named templates.

Ordering

Messages to the same recipient are sent in the order you call the API. Across different recipients there is no ordering guarantee, and none is needed.