Skip to main content
Use these practices to send WhatsApp messages reliably at production scale. You will choose the right endpoint, correlate each attempt, converge delivery state, retry safely, enforce consent, and control throughput.

Before you begin

  • Connect and register the WhatsApp business phone numbers that will send messages.
  • Store your YCloud API key on the server.
  • Configure a signed webhook endpoint for whatsapp.message.updated.
  • Define how your system records consent, opt-outs, message purpose, and retention.
  • Assign owners for sending, webhook processing, and incident response.

Choose the sending endpoint

Use the queued endpoint by default. Use direct sending only when the application must know whether WhatsApp accepted the submission before continuing. A successful response from either endpoint is not proof of delivery. Store the returned message id and use whatsapp.message.updated events to learn whether the message is sent, failed, delivered, or read.
Do not switch an entire high-volume workload to sendDirectly to reduce queue latency. Synchronous calls hold application resources and still require asynchronous status handling.

Create one internal send record

Create a durable record before calling the API. Give the record a unique business key, such as an order event ID plus the message purpose. Enforce that uniqueness in your database so concurrent workers cannot send the same business event twice. Record at least: Use an opaque externalId that does not contain message content or personal data. The API recommends a unique value, but externalId is a reference field. It is not a server-side idempotency key and does not make repeated POST requests safe.

Connect the response to status webhooks

The following example uses the same identifiers through the send workflow.

1. Send the message

2. Store the accepted response

Commit MESSAGE_ID, accepted, and the response time to the existing internal record. Do not mark the business notification as delivered.

3. Apply later status events

Match the event by whatsappMessage.id. Use externalId for business reconciliation and wamid for provider-side investigation.

Build a convergent status model

The common progression is accepted → sent → delivered → read. failed can occur before or after a sent update. Webhooks can be duplicated, delayed, or delivered out of order. A read update can also arrive without a separate delivered event. Process each event as follows:
  1. Verify the webhook signature against the raw request body.
  2. Durably store the event, using event id as the deduplication key.
  3. Return a 2xx response promptly, then process the event asynchronously.
  4. Match whatsappMessage.id to the internal send record.
  5. Store the event status and its available message timestamps. Keep the raw event metadata needed for an audit, but remove unnecessary message content.
  6. Update the current business view without discarding conflicting or later evidence. Treat read as evidence that delivery occurred even when the separate delivered event is absent.
  7. Retrieve GET /whatsapp/messages/{id} when events conflict, a terminal status is missing beyond your service objective, or the webhook pipeline was unavailable.
Do not implement the status model as a rule that only accepts a higher-ranked status. Real delivery updates do not always arrive in that order. Retain an event history and make reconciliation able to correct the current view.

Retry without creating duplicate sends

Classify the failure before retrying. A safe application policy can start with a small number of attempts, exponential delays, full jitter, and a maximum elapsed time. These are application controls, not API guarantees. Send exhausted attempts to a review queue instead of retrying forever. Before each retry:
  • Lock or atomically claim the internal business key.
  • Check whether the record already has a YCloud id or a status event.
  • Do not use a new externalId to hide an earlier ambiguous attempt.
  • Stop after the configured attempt or age limit.
  • Require a deliberate operator action before replaying an ambiguous send.

Choose templates and session messages

Use an approved template when you initiate a business message or send outside the 24-hour customer service window. Select the template category from the user’s reason for receiving the message, and keep its name, language, and variable contract in application configuration. Use text, media, interactive, location, contact, or reaction messages only when the customer service window is open and that content type is allowed. Determine the window from the customer’s most recent message. Do not infer an open window from your last outbound message. See Manage WhatsApp templates for template versioning, approval gates, locales, and rollback.

Handle media efficiently

  • Validate the file’s supported MIME type and size before upload. Do not retry an oversized or unsupported file unchanged.
  • Upload with the business phone number that will send the message.
  • Reuse the returned media ID for repeated sends of the same approved asset while it remains valid. Uploaded media persists for 30 days.
  • Store the asset checksum, MIME type, media ID, sender, and expiration time so workers do not upload the same file for every recipient.
  • Upload again after expiration or when the sender context changes.
  • Use a public URL instead when the message schema requires a link, including media in interactive message headers.
  • Stream large uploads from storage, set request timeouts, and delete temporary local files after use.
Record the consent source, purpose, time, and permitted channel before sending. Apply the latest valid opt-out across campaigns, transactional workflows where policy requires it, retries, and manual replays. For POST /whatsapp/messages, set filterUnsubscribed: true and filterBlocked: true when the workflow must enforce YCloud suppression lists. These fields default to false. They do not apply to sendDirectly, so a direct-send workflow must check suppression before the API call. Suppression filters are a final safety check, not a replacement for consent. Store only the identifiers and delivery metadata needed for the stated purpose. Exclude API keys, template variables, message bodies, and phone numbers from general application logs. Apply retention and access controls to message and webhook records.

Control batch throughput

Place batch work in a bounded queue and send through a fixed worker pool. Track concurrency separately by account and business phone number so one sender or tenant cannot consume every worker. Apply backpressure when any of these signals increase:
  • 429 responses
  • request latency and timeouts
  • 5xx responses
  • queue age or retry backlog
  • webhook lag and unresolved accepted messages
Reduce concurrency when YCloud or downstream delivery slows. Resume gradually after recovery. Do not retry failed messages faster than the original send rate. Monitor at least request volume, accepted rate, error rate by HTTP status and error code, delivery status rate, time from accepted to each later status, queue depth, oldest queue age, retry count, webhook lag, deduplication count, and reconciliation drift. Alert on sustained changes from your normal baseline, not on a single failed message.

Common anti-patterns

  • Marking a message delivered when the API returns accepted.
  • Treating externalId as a YCloud idempotency key.
  • Retrying every non-2xx response or timeout with no attempt limit.
  • Using sendDirectly for all traffic.
  • Assuming webhooks are unique, ordered, or complete.
  • Sending free-form messages outside the customer service window.
  • Uploading the same media file for every recipient.
  • Relying on suppression filters without recording consent.
  • Logging API keys, full payloads, or unnecessary personal data.
  • Starting a batch with unbounded concurrency and no backpressure.

Go-live checklist

  • The endpoint choice matches the workload and latency requirement.
  • A database uniqueness rule protects the internal business key.
  • externalId, YCloud id, and wamid have distinct documented roles.
  • Initial responses remain non-final until status evidence arrives.
  • Webhook signatures, event deduplication, fast acknowledgement, and replay are tested.
  • A scheduled retrieval job reconciles delayed or missing events.
  • Retryable and non-retryable failures have bounded handling paths.
  • Template and session-window rules are enforced before sending.
  • Media uploads are validated, reused, expired, and cleaned up safely.
  • Consent, unsubscribe, block-list, retention, and logging controls are verified.
  • Batch queues have concurrency limits, backpressure, dashboards, and alerts.
  • Operators can pause sends and review ambiguous attempts without replaying them automatically.

Send a WhatsApp message

Review request types, fields, examples, and response data.

Configure webhooks

Verify signatures and process repeated event deliveries safely.

Upload WhatsApp media

Upload supported media and reuse the returned media ID.

Handle API errors

Parse error responses and apply bounded retries.