Partners
Onboard your clientswithout touching their credentials.
Agencies and platforms resell messaging without becoming a support desk for Meta's setup. You send a link; your client authorizes with Meta; the connected sender appears in your project, on the same API as everything else you ship.
- One link per client
- One sub-account per client
- One bill, yours
What a link connects
Two routes in. Pick one per invitation.
connectionType decides which dialog your client sees and which fields the invitation will accept.
WhatsApp Business Account
whatsapp_wabaThe default. Meta's embedded signup links an official WhatsApp Business Account, and the sender is created in your project when your client finishes.
- Pre-assign one of your Zavu numbers with phoneNumberId, or leave it to them
- Restrict where their own number may come from with allowedPhoneCountries
- Completes with the WhatsApp phone number ID and its verified name
Facebook Page
messengerYour client authorizes with Facebook and picks a Page they administer. That Page's Messenger inbox — Marketplace chats included — routes to Zavu.
- They must administer at least one Page, or the invitation fails with meta_no_pages
- phoneNumberId and allowedPhoneCountries are refused with 400: a Page has no phone number
- Completes with the Facebook Page ID and the Page name
One invitation connects one channel. To onboard a client on WhatsApp and on Messenger, send two — each completes into its own sender.
A Facebook Page can only be connected to one Zavu project at a time. If your client picks a Page another project already connected, the newer connection wins and the older one is disconnected.
The state machine
You will not be watching. The webhook will.
Your client is inside Meta's dialog; all you get back is invitation.status_changed. Step through it, fork the ending, and read what actually lands on your endpoint.
POST /v1/invitations · 201
{
"invitation": {
"id": "inv_8ac31f",
"url": "https://dashboard.zavu.dev/invite/9f2b7c1e",
"connectionType": "whatsapp_waba",
"status": "pending",
"clientName": "Acme Corp",
"clientEmail": "ops@acme.com",
"expiresAt": "2026-03-01T10:00:00Z",
"viewedAt": null,
"startedAt": null,
"senderId": null,
"connectedAccount": null
}
}Fields as documented in the API reference: Invitation, InvitationStatus, invitation.status_changed.
The whole surface
Six calls, and you are a reseller.
Invitations and sub-accounts are both in the SDK. The Messenger route is shown over REST while the generated clients catch up with it.
import Zavudev from "@zavudev/sdk"
const zavu = new Zavudev({ apiKey: process.env.ZAVU_API_KEY })
// One invitation connects one channel. Send a second one for Messenger.
const { invitation } = await zavu.invitations.create({
clientName: "Acme Corp",
clientEmail: "ops@acme.com",
connectionType: "whatsapp_waba",
allowedPhoneCountries: ["US", "MX"],
expiresInDays: 14, // 1-30, defaults to 7
})
// Send this to your client. Nothing else is required of you.
console.log(invitation.url, invitation.status) // ... "pending"The cap
A client can spend your money. Decide how much.
Charges from a sub-account are billed to your team's balance. creditLimit is what stands between a client's runaway loop and your invoice — and it is in cents. Move the cap, spend against it, watch which side stops.
Set in cents on the API. 0 — or omitting the field — means no limit at all.
- Your balance
- $1200.00
- totalSpent
- $0.00
- Headroom
- $100.00
Simulated usage on the client's own API key. Amounts are illustrative.
Ledger
- Nothing spent yet.
GET /v1/sub-accounts/sub_2f91c4/balance · 200
{
"balance": 120000,
"currency": "usd",
"creditLimit": 10000,
"totalSpent": 0,
"isSubAccount": true
}The shape returned by GET /v1/sub-accounts/{id}/balance. balance is your team's, in cents, because every charge is billed to the parent.
What a sub-account is
Their project. Your account.
Its own API keys
Mint live or test keys per client. The full key is returned once, on creation; every later read gives you the prefix only.
It cannot manage siblings
Sub-account keys answer 403 on every sub-account endpoint. A client key can never enumerate, create or inspect another client.
One balance, yours
Every charge lands on the parent team's balance. You read a client's totalSpent and creditLimit without giving it any way to spend past the cap.
Closing one is clean
Deactivating a sub-account returns its remaining balance to your team and revokes all of its API keys, and tells you how many it revoked.
Before you resell on it
- One invitation connects one channel. Two channels for the same client means two invitations, each completing into its own sender.
- phoneNumberId and allowedPhoneCountries are WhatsApp-only. Sending either with connectionType messenger returns 400 rather than being ignored.
- A Facebook Page can only be connected to one Zavu project at a time. The newer connection wins and the older one is disconnected.
- An invitation expires after the days you set — between 1 and 30, defaulting to 7. Cancel a link and it stops working for good.
- creditLimit is in cents, and 0 means no limit. A cap of 2500 is $25.00, not $2,500.
- Sub-account API keys receive 403 on sub-account management. That surface belongs to the parent project's key.
Your clients, your account, your bill.
Start free, no credit card. Invitations and sub-accounts are available on every plan.