What v2 is
v2 is a second version of the Zavu REST API. It runs on the same engine as v1: the same API keys, the same sending limits, prices and reviews. v1 keeps working unchanged, and you can call both from the same code. What v2 changes is the shape:- No sender object. You send from an address, the way the recipient sees it: a phone number, an email address, a bot name.
- No
Zavu-Senderheader. Passfrom, or reply inside a thread withconversationId. - Every send says how it was routed. The
202carriesrouting: the channel, the address it left from, and why. - One webhook for the project. Every event, at one URL.
- One error shape.
{code, message, details}at the root of every error.
Base URL and authentication
from
and conversationId are not consulted.
The SDKs (
@zavudev/sdk on npm, zavudev on PyPI, and the others) call v1
today. Call v2 over HTTP: curl, fetch, or any HTTP client.Addresses
An address is where a message leaves from, written the way the recipient sees it.GET /v2/channels lists one entry per (address, type). A number that carries
WhatsApp and SMS is two entries with the same address. active: false means the
connection exists but is switched off.
Send your first message
1
Connect a channel
POST /v2/channels connects what needs no purchase and no Meta signup.
Pick one:POST /v2/numbers). WhatsApp,
Instagram and Messenger connect through Meta, from Accounts in the
dashboard.2
Send
In a new project the first channel lands on the default, so
from is not
needed.202 Accepted
3
Pick the sending address
With more than one address, name it in
from:Email domains
An email address can only be connected at a verified domain of the project:POST /v2/email-domainswith{"domain": "yourdomain.com"}. The answer has the DNS records to publish.- Publish them exactly as returned.
POST /v2/email-domains/{emailDomainId}/verify.POST /v2/channelswith{"type": "email", "address": "noreply@yourdomain.com"}.
409 email_domain_missing or 409 email_domain_not_verified, with the call
that fixes it in details.recommendation.
How a send is routed
The message leaves fromconversationId if given, else from, else the project
default. The transport is the first rule that applies, reported in
routing.reason:
The order does not compare price or check the WhatsApp 24-hour window. A
connection that is switched off is skipped. A WhatsApp-to-SMS fallback happens
after the
202, so it never appears in routing; read attemptedChannels on
the message.
When nothing can send: 409 no_channel
Every “nothing can send this” is the same answer: no channel at all, a channel
that is not connected, an email to without email, a WhatsApp-only
messageType without WhatsApp. details.connect lists what this project can
connect to reach to, with the exact request for each.
409 Conflict
request: null means the channel is connected from the dashboard.
available: false says why in note, for example one-way SMS before business
verification is approved.
Replying in a conversation
PassconversationId instead of from. The reply leaves from the address the
thread was last handled from and goes to whoever the thread is with, so to can
be omitted.
to that is not the thread’s contact is refused with 400, rather than
starting another conversation.
Webhook
One webhook per project, configured withPUT /v2/webhook, receives every event
you subscribe to. Payloads name addresses, never a sender id. See
Webhook.
Errors
Every error is flat:405 method_not_allowed, with
details.allowed and an Allow header. See Errors.
Money
Every amount in v2 is USD, rounded to 6 decimals.routing.estimatedCost is
what an SMS took from your balance when it was accepted; it is null where the
price is not known at send time (WhatsApp, email, voice). message.charged is
what an SMS has taken so far.
