Guides
Send and receive media
Send images and documents by link or uploaded media id, and download inbound media bytes through the graph media runtime.
active · reviewed 2026-07-05
Sends take either a public link (Meta fetches it) or a mediaId from a
prior uploadMedia call. Both return a waitable sent-result.
import { createWhatsApp } from "@wats/core";
const wa = createWhatsApp({
accessToken: process.env.WATS_ACCESS_TOKEN!,
phoneNumberId: process.env.WATS_PHONE_NUMBER_ID!,
});
await wa.sendImage({
to: "<recipient-e164>",
link: "https://example.com/receipt.png",
caption: "your receipt",
});
await wa.sendDocument({
to: "<recipient-e164>",
link: "https://example.com/invoice.pdf",
filename: "invoice-4821.pdf",
});Inbound media arrives as a typed message with a MediaReference carrying the
id Meta assigns. Download the bytes with the graph media runtime — a two-step
fetch: metadata by id, then the binary by URL.
import { createWhatsApp } from "@wats/core";
import { downloadMedia, downloadMediaBytes, DEFAULT_MAX_MEDIA_DOWNLOAD_BYTES } from "@wats/graph";
const wa = createWhatsApp({
accessToken: process.env.WATS_ACCESS_TOKEN!,
phoneNumberId: process.env.WATS_PHONE_NUMBER_ID!,
});
wa.onMessage(async (ctx) => {
const message = ctx.update.message;
if (message.type !== "image") return;
const meta = await downloadMedia(wa.graphClient, { mediaId: message.image.id });
const file = await downloadMediaBytes(wa.graphClient, {
url: meta.url,
expectedSha256: meta.sha256,
maxBytes: DEFAULT_MAX_MEDIA_DOWNLOAD_BYTES,
});
// file.bytes is a Uint8Array; persist it yourself
});Webhook media IDs are downloadable for 7 days. Download promptly and store
the bytes yourself; WATS does not auto-persist webhook media. For Node/Bun
file sends from disk, use the @wats/graph/node-media path helpers.