Sending messages
Send text, media, templates, and interactive messages to a contact.
A contact is an end user reachable on one of your channels, identified by a
stable id (aliased as contact_id) that is unique per phone number within your
organization. Before you can send proactively to a WhatsApp number — a to
send outside an existing conversation — that contact needs an active opt-in
record. Replies inside the 24-hour window
do not.
Record the contact and its opt-in in one call. phone is E.164. optIn.source
is required when you pass an optIn block — capture where and how consent was
given so it holds up to a WhatsApp quality review.
const contact = await wabery.contacts.enroll({ phone: "+14155550100", name: "Ada Lovelace", preferredLanguage: "en", // BCP-47; resolves locale-specific flows referenceId: "user_123", // your own id; echoed back as contact_reference metadata: { plan: "pro" }, optIn: { source: "checkout_form", // required within optIn method: "web_form", occurredAt: "2026-06-20T14:00:00Z", consentText: "I agree to receive order updates on WhatsApp.", },});wabery contacts enroll --project-id "project_id" \ --phone "+14155550100" \ --preferred-language "en" \ --metadata '{"plan":"pro"}'curl https://api.wabery.com/v1/contacts \ -H "Authorization: Bearer $WABERY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phone": "+14155550100", "name": "Ada Lovelace", "preferred_language": "en", "reference_id": "user_123", "metadata": { "plan": "pro" }, "opt_in": { "source": "checkout_form", "method": "web_form", "occurred_at": "2026-06-20T14:00:00Z", "consent_text": "I agree to receive order updates on WhatsApp." } }'Requires the contacts:write scope. project_id is optional — API keys are
project-scoped, so it defaults to the key’s project and must match it if set.
A contact response:
{ "object": "contact", "id": "contact_...", "contact_id": "contact_...", "phone": "+14155550100", "preferred_language": "en", "reference_id": "user_123", "project_id": "project_...", "status": "active"}Use id in new code; contact_id is a backward-compatible alias with the same
value. reference_id is your correlation key — it surfaces as
contact_reference on every webhook for this contact.
metadata is shallow-merged into the existing value; preferredLanguage: null clears it. Requires contacts:write.
await wabery.contacts.update("contact_...", { preferredLanguage: "es", metadata: { linked: true }, // merged, not replaced});wabery contacts update "contact_..." --preferred-language "es" \ --metadata '{"linked": true}'curl -X PATCH https://api.wabery.com/v1/contacts/contact_... \ -H "Authorization: Bearer $WABERY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "preferred_language": "es", "metadata": { "linked": true } }'Cursor-paginated with limit and startingAfter (see
Pagination). Requires contacts:read.
const { data, has_more } = await wabery.contacts.list({ limit: 50 });
// Or stream every page without managing the cursor:for await (const contact of wabery.contacts.listAll()) { console.log(contact.id, contact.phone);}unenroll deletes the contact record. Pass erase: true to also erase
retained personal data (requires the contacts:erase scope) — use it for GDPR
/ right-to-be-forgotten requests.
await wabery.contacts.unenroll("contact_...", { erase: true });Enrollment is a server-side action with a secret key — you already hold the
number and consent. To let a customer opt in from your app without a secret
key, mint a browser-safe registration intent
instead: they tap a wa.me link, message your number, and Wabery links the
WhatsApp identity to your customer_reference.
Sending messages
Send text, media, templates, and interactive messages to a contact.
Registration intents
Browser-safe opt-in links that link a WhatsApp identity to your user id.
Conversations & history
List a contact’s threads and read message history.