Pular para o conteúdo
Start free

Wabery CLI

Este conteúdo não está disponível em sua língua ainda.

Install the CLI:

Terminal window
npm i -g @wabery/cli
wabery login

Use it to manage the whole project from a terminal. If you would rather describe the result to an AI agent, connect the hosted MCP server instead.

WhatsApp Groups are available through wabery groups. Use group_id for a group target; it is an opaque WhatsApp ID and is never a phone number passed as to. MCP group mutations and sends require explicit confirmation; direct CLI commands execute immediately like the CLI’s other write commands. See the WhatsApp Groups guide for Cloud API eligibility, limits, unsupported features, and webhook fields.

Group list commands use cursor pagination: --limit defaults to 25 and accepts 1–1024, --starting-after and --ending-before are the canonical opaque cursor flags, and --after/--before are aliases. Never substitute a group ID for a cursor.

Terminal window
wabery groups list --channel-id "channel_id" --limit 25 \
--starting-after "<opaque-cursor>"
wabery groups create --channel-id "channel_id" --subject "Support" \
--idempotency-key "create-support-group-2026-08-22"
wabery groups join-requests "group_id" --channel-id "channel_id" \
--ending-before "<opaque-cursor>"
# Group sends support text, media (including sticker), text/media templates,
# and pin or unpin only.
wabery messages send --channel-id "channel_id" \
--group-id "opaque_group_id" --sticker-link "https://example.com/sticker.webp" \
--idempotency-key "support-group-2026-08-22"

For a group target, --group-id, --conversation-id, and --to are mutually exclusive. Pin JSON uses REST’s pin.expiration_days (1–30); the SDK spelling is expirationDays. Group sends do not support location, reaction, contacts, commerce, interactive, calls, ephemeral, view-once, authentication, edit, or delete operations.

Group sends require --idempotency-key. Generate it once and reuse it for every retry. If the API returns object: "message_request", status: "processing", keep that key for reconciliation rather than creating a new key.

Complete WhatsApp Groups command reference

Section titled “Complete WhatsApp Groups command reference”

These are the shipped group commands. Every group command needs --channel-id; commands with a group ID accept it positionally or through --group-id (the examples use the positional form). JSON flags accept inline JSON or @file.json.

# Read groups and group details
wabery groups list --channel-id <channel_id> [--limit <1-1024>] \
[--starting-after <opaque-cursor>] [--ending-before <opaque-cursor>] \
[--after <opaque-cursor>] [--before <opaque-cursor>]
wabery groups get <group_id> --channel-id <channel_id>
wabery groups get --group-id <group_id> --channel-id <channel_id>
# Create; --idempotency-key is always required, including with --body
wabery groups create --channel-id <channel_id> --subject <subject> \
[--description <description>] \
[--join-approval-mode auto_approve|approval_required] \
--idempotency-key <stable-key>
wabery groups create --channel-id <channel_id> --body '<json-or-@file>' \
--idempotency-key <stable-key>
# Delete, or update subject/description
wabery groups delete <group_id> --channel-id <channel_id>
wabery groups settings <group_id> --channel-id <channel_id> \
[--subject <subject>] [--description <description>]
wabery groups settings <group_id> --channel-id <channel_id> \
--body '<json-or-@file>'
# Upload a JPEG profile picture; subject/description may be included
wabery groups settings <group_id> --channel-id <channel_id> \
--profile-picture <jpeg-file> [--subject <subject>] [--description <description>]
# Read the current invite, or invalidate it and get a replacement
wabery groups invite-link <group_id> --channel-id <channel_id>
wabery groups invite-link <group_id> --channel-id <channel_id> reset
wabery groups invite-link <group_id> --channel-id <channel_id> --reset
# Join requests: list, approve, or reject comma-separated opaque IDs
wabery groups join-requests <group_id> --channel-id <channel_id> list \
[--limit <1-1024>] [--starting-after <opaque-cursor>] \
[--ending-before <opaque-cursor>] [--after <opaque-cursor>] [--before <opaque-cursor>]
wabery groups join-requests <group_id> --channel-id <channel_id> approve \
--join-request-ids <id1,id2>
wabery groups join-requests <group_id> --channel-id <channel_id> reject \
--join-request-ids <id1,id2>
# --action list|approve|reject is an equivalent flag form; --body '<json>'
# can replace --join-request-ids for approve/reject.
# Remove users; --users is a comma-separated list of WhatsApp user IDs
wabery groups remove-participants <group_id> --channel-id <channel_id> \
--users <user1,user2>
wabery groups remove-participants <group_id> --channel-id <channel_id> \
--body '<json-or-@file>'
# Send to a group through the messages command. Exactly one supported content
# field is required; --body can express any REST-supported group payload.
wabery messages send --channel-id <channel_id> --group-id <opaque_group_id> \
--text <text> --idempotency-key <stable-key>
wabery messages send --channel-id <channel_id> --group-id <opaque_group_id> \
--media '<json>' --idempotency-key <stable-key>
wabery messages send --channel-id <channel_id> --group-id <opaque_group_id> \
--template '<json>' --idempotency-key <stable-key>
wabery messages send --channel-id <channel_id> --group-id <opaque_group_id> \
--sticker-link <https-url> --idempotency-key <stable-key>
wabery messages send --body '<json-or-@file>'

--profile-picture must be a JPEG; Wabery sends it as the multipart profile_picture_file field. Group sends support text, media (including stickers), text/media templates, and pin/unpin JSON payloads only. Keep the same send or create idempotency key after a processing response. CLI writes execute immediately; the CLI does not add the MCP confirmation gate.

Install it globally, then sign in:

Terminal window
npm i -g @wabery/cli
wabery login

wabery login authorizes the CLI in your browser (--no-open prints a URL instead), asks you to choose a project, creates a key scoped to that project, then shows the key once. Paste it back into the waiting terminal; the CLI stores it locally so future CLI and MCP commands are authenticated. Run wabery doctor to confirm. To override, set WABERY_API_KEY (and optionally WABERY_BASE_URL, which defaults to the API base https://api.wabery.com/v1 — not the dashboard origin).

Prefer not to install globally? Run any wabery command on demand through your package runner — handy for CI or a one-off wabery login:

Terminal window
npx wabery login
npx wabery doctor

After login, wabery init creates starter files for your app without overwriting existing files:

Terminal window
wabery init --name "My project"

It writes .env.wabery, wabery.config.json, and a wabery-webhook-handler.ts stub. Load .env.wabery in your app, edit the webhook URL in wabery.config.json, then apply it with wabery config apply wabery.config.json. Config apply can create or update a hosted-agent Draft only. It cannot edit Live or publish the agent to customers.

Terminal window
# verify your API key and base URL; also flags channels that drop inbound
# (the `channels` check lists any `routing_warnings`)
wabery doctor
# confirm the project this key is scoped to
wabery projects list
# for a new sandbox project: text the join code to the sandbox,
# send one normal WhatsApp message, then inspect the conversation
wabery projects get "project_id" # read join_code + enrollment_channel.phone_number
wabery channels list
wabery conversations list
wabery conversations messages "conversation_id"
# reply inside the open messaging window
wabery messages send --channel-id "channel_id" \
--conversation-id "conversation_id" \
--text "Thanks for your message"
# send richer WhatsApp payloads
wabery messages send --channel-id "channel_id" \
--conversation-id "conversation_id" \
--latitude 37.7749 --longitude -122.4194 --location-name "Office"
wabery messages send --channel-id "channel_id" \
--conversation-id "conversation_id" \
--sticker-link "https://example.com/sticker.webp"
# create a starter config, then validate it
wabery config init wabery.config.json --project-id "project_id"
wabery config validate wabery.config.json
# enroll a WhatsApp contact for testing (optionally with a language)
wabery contacts enroll --project-id "project_id" --phone "+14155550123" \
--preferred-language "es"
# update a contact's language or metadata later (metadata is shallow-merged)
wabery contacts update "contact_id" --preferred-language "id" \
--metadata '{"linked": true}'
# import a consented CSV audience, then poll the returned import id
wabery contacts import contacts.csv --phone-column phone \
--name-column name --language-column language --tags-column tags \
--consent '{"categories":["MARKETING"],"source":"signup_form","method":"web_form"}'
wabery contacts import-status "import_id"
# mint a single-use WhatsApp registration link
wabery registration-intents create --customer-reference "user_123" \
--metadata '{"plan": "starter"}'
wabery registration-intents get "intent_id"
# send a flow; use --config-key to pick the variant for the contact's language
wabery flows send "flow_id" --channel-id "channel_id" --contact-id "contact_id"
wabery flows send --config-key "lead_intake" --locale "es" \
--channel-id "channel_id" --contact-id "contact_id"
# check a queued message or wait for a template approval in scripts
wabery messages get "message_id"
wabery templates wait "template_id" --wait=86400
# inspect channels; `routing_warning` flags a channel that silently drops inbound
wabery channels list
wabery channels get "channel_id"
# forward a dedicated number's inbound to your webhook (overrides project routing)
wabery channels update "channel_id" --routing-mode EXTERNAL
# or set the project-wide default that new channels inherit
wabery projects update "project_id" --routing-mode EXTERNAL
# opt into group.lifecycle/group.participants/group.settings/group.status
wabery projects update "project_id" --group-webhook-events-enabled true
# deploy hosted logic for tools or message-triggered workflows
wabery functions create --slug quote-customer \
--name "Quote customer" --trigger-type ANY_MESSAGE
wabery functions deploy "function_id" --source ./quote-customer.ts
wabery functions update "function_id" --active true
wabery functions test "function_id" --text "I need a quote"
wabery functions update "function_id" \
--expose-as-mcp-tool true \
--input-schema '{"type":"object"}'
wabery functions invoke "function_id" --arguments '{"orderId":"ord_123"}'
wabery functions logs "function_id"

A broadcast sends an approved WhatsApp template to a frozen, consent-eligible audience. It requires a dedicated Meta Cloud API channel; the shared sandbox cannot send broadcasts. Prepare and inspect the audience before the irreversible send step.

First create broadcast.json:

{
"name": "August launch",
"channelId": "channel_...",
"category": "MARKETING",
"templateName": "august_launch",
"fallbackLanguage": "en_US",
"variants": [
{
"templateId": "template_...",
"language": "en_US",
"parameterMappings": [
{
"component": "body",
"index": 0,
"parameterType": "text",
"source": "name",
"fallback": "there"
}
]
}
]
}

Then create, prepare, and review the draft:

Terminal window
wabery broadcasts create --body @broadcast.json
# audience.json must contain exactly one of contactIds, importId, or filter
wabery broadcasts prepare "broadcast_id" \
--body '{"filter":{"tags":["launch-list"],"languages":["en","es"]}}'
# preparation is asynchronous: poll until status is ready
wabery broadcasts get "broadcast_id"
# inspect the frozen snapshot, including skipped or failed recipients
wabery broadcasts recipients "broadcast_id"
wabery broadcasts recipients "broadcast_id" --limit 100
wabery broadcasts recipients "broadcast_id" --status skipped

Only after the returned counts match the intended audience, send now or schedule an absolute instant:

Terminal window
wabery broadcasts send "broadcast_id" \
--idempotency-key "august-launch-send"
wabery broadcasts schedule "broadcast_id" \
--scheduled-at "2026-08-01T10:00:00Z" \
--timezone "Europe/Amsterdam" \
--idempotency-key "august-launch-schedule"

Monitor, reuse, or stop a campaign:

Terminal window
wabery broadcasts list --status sending
wabery broadcasts get "broadcast_id"
wabery broadcasts duplicate "broadcast_id"
wabery broadcasts cancel "broadcast_id"

The CLI generates an idempotency key for mutating broadcast commands when one is not supplied. Pass your own stable key in scripts. Duplicating copies the template configuration into a new draft, not the previous audience snapshot. Canceling stops recipients that have not been dispatched; messages already accepted by Meta cannot be recalled. See WhatsApp broadcasts for consent, frequency, status, and webhook behavior.

The CLI also prints config for the local Wabery MCP server, so Claude Code, Codex, and OpenCode can call Wabery directly:

Terminal window
wabery mcp-config claude --raw
wabery mcp-config codex --raw
wabery mcp-config opencode --raw

Prefer no install? Wabery also has a hosted MCP server with OAuth sign-in. See the WhatsApp MCP Server docs for the hosted setup, the full list of exposed tools, and a worked example prompt.