TL;DR
- The dashboard is organized by what you do: seven rows, with your channels and numbers in one Channels area.
- Accounts created from October 19, 2026 get 2.0. Older accounts can switch from the top bar and switch back.
- API v2 sends from an address. You pass
fromor reply withconversationId, and every202says how it was routed. - API v1 keeps working, with the same key, the same data and no deadline to move.
- The SDKs still call v1, so call v2 over HTTP for now.
Today we are launching Zavu 2.0: a new dashboard and a second version of our multichannel messaging API. The engine underneath is the one you already use. What changes is how you find your way through it, and how your code talks to it.
This post covers what changed, who gets it, how API v2 differs from v1 with a request side by side, and where to start if you are building something this week.
What changed in the dashboard
We did not start from a design. We started from how people used the previous one. Between July and September, the most opened rows in the sidebar were Home, Inbox, Accounts, Phone Numbers and Senders. And Accounts, Senders and Phone Numbers were opened one after another, in a loop, by people looking for the same thing: where is my channel, and why can it not send.
So 2.0 is organized by what you do, not by how the API is built. Seven rows:
- Home, Conversations and Contacts: the daily work.
- Under Build: Campaigns, Agents, Channels and Developers.
Every screen that existed is still reachable, inside the area it belongs to. Nothing was deleted to make the menu shorter.
Channels, in one place
Accounts, Senders and Phone Numbers are now one area, Channels. It is grouped under three small headings:
- Connect: connect WhatsApp, see your connected channels, send client invitations, and manage phone numbers. WhatsApp has its own connection screen, which lists the requirements before Meta's signup opens.
- Test: the Playground and the Sandbox, right below the numbers a message leaves from. When a channel goes live, this is where you try it.
- Compliance: limits and verification in one screen, so you see your daily ceilings before a send hits them rather than after.
Senders are no longer a screen. Connecting a channel creates what it needs. The ID that API v1 still uses lives under Developers → Sender IDs, marked API v1.
Home starts from your goal
The first thing Home asks is what you want to get done: talk to your customers, notify from your app, send a campaign, or connect your clients' channels if you are an agency. Each goal says what it recommends and why. Talking to customers, for instance, points out that Telegram connects in minutes while WhatsApp needs a Meta Business account.
Then Home shows the steps left for that goal and checks each one off when it actually happens: a channel connected, a reply sent from Conversations, an agent answering. Your API key and a first request are there, ready to copy.
Zavu Assistant
The assistant had three names in the previous interface. In 2.0 it has one, Zavu Assistant, in the app bar and on Home. It receives the goal you picked, so a question starts from where you are rather than from zero. You can also type your goal to it directly from Home.
The other screens say what is missing
A large part of 2.0 is screens that explain themselves:
- Conversations shows why a message failed on the message itself, and lets you pick the channel to reply on.
- Campaigns says what each channel needs before you pick it, shows the estimated cost and your balance before you send, and lets you send yourself a test. The test is a real message and is charged like any other.
- Agents tell you why an agent did not answer and how to fix it.
- Developers holds API keys, Sender IDs, webhooks, logs and integrations. Code samples use API v2, and each one can be switched to v1.
Who gets Zavu 2.0
- Accounts created from October 19, 2026 get 2.0.
- Older accounts keep the previous interface and see an invitation. You can switch from the top bar, and switch back the same way.
- The choice is yours, not the workspace's: the rest of your team keeps theirs.
Both versions show the same account. Your data, your billing and your API v1 integration are the same whichever one you use.
API v2
API v2 runs on the same engine as v1: the same API keys, the same sending limits, prices and reviews. What changes is the shape.
- No sender object. You send from an address, written the way the recipient sees it: a phone number, an email address, a bot's
@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, the reason, andestimatedCost. - One webhook for the project.
PUT /v2/webhookreceives every event, from every address. The secret is returned once, on the201that creates it. - One error shape.
{code, message, details}at the root of every error. - One answer for "nothing can send this".
409 no_channel, withdetails.connectlisting what you can connect to reach that recipient and the exact request for each.
Before and after
The same message, on v1 and on v2:
terminal# v1: the sending identity is a sender id, in a header curl -X POST https://api.zavu.dev/v1/messages \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Zavu-Sender: kd7abc123def456" \ -H "Content-Type: application/json" \ -d '{"to": "+14155550123", "text": "Your code is 123456."}'
terminal# v2: the sending identity is an address, in the body curl -X POST https://api.zavu.dev/v2/messages \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"from": "+13125551212", "to": "+14155550123", "text": "Your code is 123456."}'
The v2 answer, abridged, for a project whose number has an approved 10DLC campaign. It names addresses, never a sender id, and tells you what happened:
JSON{ "message": { "id": "jd7x2k3m4n5p6q7r8s9t0", "to": "+14155550123", "from": "+13125551212", "channel": "sms", "status": "queued" }, "routing": { "channel": "sms", "from": "+13125551212", "reason": "auto_order", "estimatedCost": 0.0079 } }
reason is the first rule that applied: explicit when you named channel, recipient_type when to is an email address, message_type when the message type only exists on WhatsApp, conversation on a reply, sandbox with a test-mode key, and auto_order otherwise: the first active transport, for a phone number WhatsApp, then SMS, then one-way SMS. The order does not compare prices. estimatedCost is what an SMS took from your balance when it was accepted, and null where the price is not known at send time. The amount above is illustrative.
One thing worth saying for US numbers: SMS and one-way SMS to a +1 number need an approved 10DLC campaign. Without one, v2 answers 403 ten_dlc_required with the registration as API calls, in order, and the channels that reach the same person without 10DLC, such as email or Telegram.
Connecting a channel from code
POST /v2/channels connects what needs no purchase and no Meta signup: an email address at a verified domain, a Telegram bot from its token, or one-way SMS. Two-way SMS and voice come with a number of your own (POST /v2/numbers buys it and turns SMS on in one call). WhatsApp, Instagram and Messenger connect through Meta, from Channels in the dashboard.
If you send before anything can reach the recipient, you do not get a vague 400. You get this (abridged):
JSON{ "code": "no_channel", "message": "This project has no channel that can send to +14155550123 yet.", "details": { "connect": [ { "type": "sms", "request": { "method": "POST", "path": "/v2/numbers" }, "available": true }, { "type": "whatsapp", "request": null, "available": true } ] } }
request: null means that channel is connected from the dashboard. The full shapes are in the API v2 overview, addresses and channels and errors.
v1 keeps working
API v1 is frozen, not retired. Its endpoints, payloads and webhooks keep working exactly as they do today, and there is no deadline to move.
You can migrate one call at a time. Both versions take the same API key and share the same data: a message, conversation, contact, campaign or agent created through one is read through the other with the same ID. Every entry of GET /v2/channels carries v1SenderId, the value to keep sending as Zavu-Sender on the calls you have not moved yet.
Webhooks move the same way. After you create the v2 webhook, your v1 sender webhooks keep receiving events, so each event reaches both. When your receiver handles the v2 payload, PUT /v2/webhook with "disableSenderWebhooks": true switches the v1 ones off and keeps their configuration. Details in Webhook.
Some areas have no v2 endpoint yet and stay on v1 with the same key: function code and deployments, voice calls, 10DLC registration, regulatory documents, agent tools and knowledge bases, memory, and account endpoints such as balance and sub-accounts. The full list, and everything that answers differently on v2, is in Migrate from v1.
The SDKs still call v1
@zavudev/sdk on npm, zavudev on PyPI and the other SDKs call v1 today. Call v2 over HTTP: curl, fetch, requests, any client. The dashboard's code samples default to v2; the SDK tab says it calls v1.
Where to start
Five tutorials, each built on API v2 from the first request:
- Appointment reminders on WhatsApp: reminders a clinic sends from an approved template, and confirmations that come back as replies.
- OTP verification codes over an API: generate a code, send it on the channel that reaches the person, and verify it on your side.
- An AI chatbot for an online store: an agent that answers customers on a channel you connect, with Conversations for when a person needs to step in.
- Order notifications for e-commerce: confirmations and shipping updates sent from your backend when an order changes state.
- Real estate leads on WhatsApp: capture a lead, answer within the hour, and keep every conversation in one place.
If you are new to Zavu, getting started with the Zavu API covers the basics, and the messaging API guide explains how channels compare. If you already have a v1 integration, nothing breaks today. Move when it is useful to you, one call at a time.