wats.sh
Guides

Handle status callbacks

Track sent, delivered, read, and failed status webhooks with onStatus, typed filters, and per-send waiters.

active · reviewed 2026-07-05

A send accepted with HTTP 200 only proves Meta took the request. Delivered, read, and failed state arrives as inbound status webhooks. onStatus registers a handler that fires on every status update; the typed filter namespace narrows to a specific status.

import { createWhatsApp } from "@wats/core";
import { status } from "@wats/core/filtersTyped";

const wa = createWhatsApp({
  accessToken: process.env.WATS_ACCESS_TOKEN!,
  phoneNumberId: process.env.WATS_PHONE_NUMBER_ID!,
});

// Broad: every status update.
wa.onStatus((ctx) => {
  const s = ctx.update.status;
  console.log(s.id, s.status); // wamid.HR... delivered
});

// Narrow: only failures.
wa.on(status.failed(), (ctx) => {
  const errors = ctx.update.status.errors;
  // surface to your alerting
});

For a single send, the waitable result resolves on the matching status for that message id — no manual id correlation:

const sent = await wa.sendText({ to: "<recipient-e164>", text: "ship notice" });

await sent.waitUntilDelivered();
await sent.waitUntilRead({ timeoutMs: 5 * 60_000 });

status.sent(), status.delivered(), status.read(), and status.failed() are the four statuses you usually branch on. Failed updates carry an errors array from Meta; inspect it before retrying, because Meta retries the webhook until you acknowledge it.

On this page