API v2
Call Zavu API v2 from the TypeScript SDK as client.v2: send from an address, connect channels, and read flat errors, with the same client and API key as v1.
@zavudev/sdk 0.59.0 and later calls API v2 as client.v2,
on the same client, API key, retries and pagination as v1. v1 stays where it
was: client.messages is v1, client.v2.messages is v2, and the two can be
mixed in one codebase.
terminalnpm add @zavudev/sdk@^0.59.0
TypeScriptimport Zavudev from '@zavudev/sdk'; const zavu = new Zavudev(); // reads ZAVUDEV_API_KEY const { message, routing } = await zavu.v2.messages.send({ from: '+13125551212', to: '+56912345678', text: 'Your code is 123456.', });
Ids are positional
Every id in a v2 path is an argument, in the order the path has it. Body and query fields go in the object after them.
TypeScriptawait zavu.v2.channels.activate('+13125551212', 'whatsapp'); await zavu.v2.channels.disconnect('@acme_bot', 'telegram'); await zavu.v2.agents.channels.disconnect('agent_abc123', '+13125551212', 'sms'); await zavu.v2.templates.submit('tmpl_abc123', { from: '+13125551212' });
Pass an address as you read it from GET /v2/channels. The SDK puts it in the
path for you; you do not encode the + yourself.
Types
v2's Message, Contact and Template are not v1's, so v2's types have their
own entry point:
TypeScriptimport type { MessageSendParams, ChannelEntry } from '@zavudev/sdk/v2';
The root of @zavudev/sdk keeps exporting v1's types, as before.
Lists
A list call pages for you. Iterate it to follow nextCursor to the end, or
read one page:
TypeScriptfor await (const entry of zavu.v2.channels.list()) { console.log(entry.address, entry.type, entry.active); } const page = await zavu.v2.conversations.list({ limit: 20 });
Errors
A failed call throws the same classes as v1, from the root of the package. A v2
error body is {code, message, details} at the root, and the SDK keeps it on
error.error:
TypeScripttry { await zavu.v2.messages.send({ to: '+56912345678', text: 'Hi' }); } catch (err) { if (!(err instanceof Zavudev.ConflictError)) throw err; const body = err.error as { code?: string; details?: { connect?: unknown[] } } | undefined; if (body?.code !== 'no_channel') throw err; console.log(body.details?.connect); // the channels you could connect to send this }
A 409 is a ConflictError and is not retried: v2 answers it with
x-should-retry: false, and the SDK reads that header. See
Errors.
Methods
| Method | Endpoint |
|---|---|
client.v2.messages.send(body) | POST /v2/messages |
client.v2.messages.list(query) | GET /v2/messages |
client.v2.messages.retrieve(messageID) | GET /v2/messages/{messageId} |
client.v2.conversations.list(query) | GET /v2/conversations |
client.v2.conversations.retrieve(conversationID) | GET /v2/conversations/{conversationId} |
client.v2.conversations.listMessages(conversationID, query) | GET /v2/conversations/{conversationId}/messages |
client.v2.conversations.markAsRead(conversationID) | POST /v2/conversations/{conversationId}/read |
client.v2.contacts.list(query) | GET /v2/contacts |
client.v2.contacts.create(body) | POST /v2/contacts |
client.v2.contacts.retrieve(contactID) | GET /v2/contacts/{contactId} |
client.v2.contacts.update(contactID, body) | PATCH /v2/contacts/{contactId} |
client.v2.contacts.delete(contactID) | DELETE /v2/contacts/{contactId} |
client.v2.channels.list(query) | GET /v2/channels |
client.v2.channels.connect(body) | POST /v2/channels |
client.v2.channels.retrieve(address) | GET /v2/channels/{address} |
client.v2.channels.activate(address, type) | POST /v2/channels/{address}/{type}/activate |
client.v2.channels.deactivate(address, type) | POST /v2/channels/{address}/{type}/deactivate |
client.v2.channels.disconnect(address, type) | DELETE /v2/channels/{address}/{type} |
client.v2.templates.list(query) | GET /v2/templates |
client.v2.templates.create(body) | POST /v2/templates |
client.v2.templates.retrieve(templateID) | GET /v2/templates/{templateId} |
client.v2.templates.delete(templateID) | DELETE /v2/templates/{templateId} |
client.v2.templates.submit(templateID, body) | POST /v2/templates/{templateId}/submit |
client.v2.campaigns.list(query) | GET /v2/campaigns |
client.v2.campaigns.create(body) | POST /v2/campaigns |
client.v2.campaigns.retrieve(campaignID) | GET /v2/campaigns/{campaignId} |
client.v2.campaigns.delete(campaignID) | DELETE /v2/campaigns/{campaignId} |
client.v2.campaigns.recipients.add(campaignID, body) | POST /v2/campaigns/{campaignId}/recipients |
client.v2.campaigns.send(campaignID, body) | POST /v2/campaigns/{campaignId}/send |
client.v2.campaigns.progress(campaignID) | GET /v2/campaigns/{campaignId}/progress |
client.v2.campaigns.cancel(campaignID) | POST /v2/campaigns/{campaignId}/cancel |
client.v2.webhook.retrieve() | GET /v2/webhook |
client.v2.webhook.set(body) | PUT /v2/webhook |
client.v2.webhook.delete() | DELETE /v2/webhook |
client.v2.webhook.rotateSecret() | POST /v2/webhook/secret |
client.v2.agents.list(query) | GET /v2/agents |
client.v2.agents.create(body) | POST /v2/agents |
client.v2.agents.retrieve(agentID) | GET /v2/agents/{agentId} |
client.v2.agents.update(agentID, body) | PATCH /v2/agents/{agentId} |
client.v2.agents.delete(agentID) | DELETE /v2/agents/{agentId} |
client.v2.agents.test(agentID, body) | POST /v2/agents/{agentId}/test |
client.v2.agents.channels.connect(agentID, body) | POST /v2/agents/{agentId}/channels |
client.v2.agents.channels.disconnect(agentID, address, type) | DELETE /v2/agents/{agentId}/channels/{address}/{type} |
client.v2.numbers.searchAvailable(query) | GET /v2/numbers/available |
client.v2.numbers.purchase(body) | POST /v2/numbers |
client.v2.emailDomains.list() | GET /v2/email-domains |
client.v2.emailDomains.create(body) | POST /v2/email-domains |
client.v2.emailDomains.retrieve(emailDomainID) | GET /v2/email-domains/{emailDomainId} |
client.v2.emailDomains.delete(emailDomainID) | DELETE /v2/email-domains/{emailDomainId} |
client.v2.emailDomains.verify(emailDomainID) | POST /v2/email-domains/{emailDomainId}/verify |
client.v2.functions.list(query) | GET /v2/functions |
client.v2.functions.retrieve(functionID) | GET /v2/functions/{functionId} |
client.v2.functions.update(functionID, body) | PATCH /v2/functions/{functionId} |
What v2 does not cover (voice calls, 10DLC, memory, sub-accounts and the rest listed in Migrate from v1) stays on the v1 methods of the same client.