@zavudev/sdk 0.58.1 → 0.59.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +18 -0
  3. package/client.d.mts +2 -0
  4. package/client.d.mts.map +1 -1
  5. package/client.d.ts +2 -0
  6. package/client.d.ts.map +1 -1
  7. package/client.js +2 -0
  8. package/client.js.map +1 -1
  9. package/client.mjs +2 -0
  10. package/client.mjs.map +1 -1
  11. package/package.json +21 -1
  12. package/src/client.ts +2 -0
  13. package/src/types.ts +29 -12
  14. package/src/v2/index.ts +4 -0
  15. package/src/v2/resources/agents/agents.ts +142 -0
  16. package/src/v2/resources/agents/channels.ts +66 -0
  17. package/src/v2/resources/agents/index.ts +18 -0
  18. package/src/v2/resources/agents.ts +3 -0
  19. package/src/v2/resources/campaigns/campaigns.ts +178 -0
  20. package/src/v2/resources/campaigns/index.ts +27 -0
  21. package/src/v2/resources/campaigns/recipients.ts +62 -0
  22. package/src/v2/resources/campaigns.ts +3 -0
  23. package/src/v2/resources/channels.ts +156 -0
  24. package/src/v2/resources/contacts.ts +112 -0
  25. package/src/v2/resources/conversations.ts +89 -0
  26. package/src/v2/resources/email-domains.ts +107 -0
  27. package/src/v2/resources/functions.ts +73 -0
  28. package/src/v2/resources/index.ts +138 -0
  29. package/src/v2/resources/messages.ts +129 -0
  30. package/src/v2/resources/numbers.ts +74 -0
  31. package/src/v2/resources/templates.ts +104 -0
  32. package/src/v2/resources/webhook.ts +102 -0
  33. package/src/v2/types.ts +2429 -0
  34. package/src/v2/v2.ts +315 -0
  35. package/src/v2.ts +3 -0
  36. package/src/version.ts +1 -1
  37. package/types.d.mts +29 -12
  38. package/types.d.mts.map +1 -1
  39. package/types.d.ts +29 -12
  40. package/types.d.ts.map +1 -1
  41. package/v2/index.d.mts +3 -0
  42. package/v2/index.d.mts.map +1 -0
  43. package/v2/index.d.ts +3 -0
  44. package/v2/index.d.ts.map +1 -0
  45. package/v2/index.js +9 -0
  46. package/v2/index.js.map +1 -0
  47. package/v2/index.mjs +4 -0
  48. package/v2/index.mjs.map +1 -0
  49. package/v2/resources/agents/agents.d.mts +81 -0
  50. package/v2/resources/agents/agents.d.mts.map +1 -0
  51. package/v2/resources/agents/agents.d.ts +81 -0
  52. package/v2/resources/agents/agents.d.ts.map +1 -0
  53. package/v2/resources/agents/agents.js +88 -0
  54. package/v2/resources/agents/agents.js.map +1 -0
  55. package/v2/resources/agents/agents.mjs +83 -0
  56. package/v2/resources/agents/agents.mjs.map +1 -0
  57. package/v2/resources/agents/channels.d.mts +39 -0
  58. package/v2/resources/agents/channels.d.mts.map +1 -0
  59. package/v2/resources/agents/channels.d.ts +39 -0
  60. package/v2/resources/agents/channels.d.ts.map +1 -0
  61. package/v2/resources/agents/channels.js +44 -0
  62. package/v2/resources/agents/channels.js.map +1 -0
  63. package/v2/resources/agents/channels.mjs +40 -0
  64. package/v2/resources/agents/channels.mjs.map +1 -0
  65. package/v2/resources/agents/index.d.mts +3 -0
  66. package/v2/resources/agents/index.d.mts.map +1 -0
  67. package/v2/resources/agents/index.d.ts +3 -0
  68. package/v2/resources/agents/index.d.ts.map +1 -0
  69. package/v2/resources/agents/index.js +9 -0
  70. package/v2/resources/agents/index.js.map +1 -0
  71. package/v2/resources/agents/index.mjs +4 -0
  72. package/v2/resources/agents/index.mjs.map +1 -0
  73. package/v2/resources/agents.d.mts +2 -0
  74. package/v2/resources/agents.d.mts.map +1 -0
  75. package/v2/resources/agents.d.ts +2 -0
  76. package/v2/resources/agents.d.ts.map +1 -0
  77. package/v2/resources/agents.js +6 -0
  78. package/v2/resources/agents.js.map +1 -0
  79. package/v2/resources/agents.mjs +3 -0
  80. package/v2/resources/agents.mjs.map +1 -0
  81. package/v2/resources/campaigns/campaigns.d.mts +100 -0
  82. package/v2/resources/campaigns/campaigns.d.mts.map +1 -0
  83. package/v2/resources/campaigns/campaigns.d.ts +100 -0
  84. package/v2/resources/campaigns/campaigns.d.ts.map +1 -0
  85. package/v2/resources/campaigns/campaigns.js +106 -0
  86. package/v2/resources/campaigns/campaigns.js.map +1 -0
  87. package/v2/resources/campaigns/campaigns.mjs +101 -0
  88. package/v2/resources/campaigns/campaigns.mjs.map +1 -0
  89. package/v2/resources/campaigns/index.d.mts +3 -0
  90. package/v2/resources/campaigns/index.d.mts.map +1 -0
  91. package/v2/resources/campaigns/index.d.ts +3 -0
  92. package/v2/resources/campaigns/index.d.ts.map +1 -0
  93. package/v2/resources/campaigns/index.js +9 -0
  94. package/v2/resources/campaigns/index.js.map +1 -0
  95. package/v2/resources/campaigns/index.mjs +4 -0
  96. package/v2/resources/campaigns/index.mjs.map +1 -0
  97. package/v2/resources/campaigns/recipients.d.mts +43 -0
  98. package/v2/resources/campaigns/recipients.d.mts.map +1 -0
  99. package/v2/resources/campaigns/recipients.d.ts +43 -0
  100. package/v2/resources/campaigns/recipients.d.ts.map +1 -0
  101. package/v2/resources/campaigns/recipients.js +41 -0
  102. package/v2/resources/campaigns/recipients.js.map +1 -0
  103. package/v2/resources/campaigns/recipients.mjs +37 -0
  104. package/v2/resources/campaigns/recipients.mjs.map +1 -0
  105. package/v2/resources/campaigns.d.mts +2 -0
  106. package/v2/resources/campaigns.d.mts.map +1 -0
  107. package/v2/resources/campaigns.d.ts +2 -0
  108. package/v2/resources/campaigns.d.ts.map +1 -0
  109. package/v2/resources/campaigns.js +6 -0
  110. package/v2/resources/campaigns.js.map +1 -0
  111. package/v2/resources/campaigns.mjs +3 -0
  112. package/v2/resources/campaigns.mjs.map +1 -0
  113. package/v2/resources/channels.d.mts +101 -0
  114. package/v2/resources/channels.d.mts.map +1 -0
  115. package/v2/resources/channels.d.ts +101 -0
  116. package/v2/resources/channels.d.ts.map +1 -0
  117. package/v2/resources/channels.js +107 -0
  118. package/v2/resources/channels.js.map +1 -0
  119. package/v2/resources/channels.mjs +103 -0
  120. package/v2/resources/channels.mjs.map +1 -0
  121. package/v2/resources/contacts.d.mts +62 -0
  122. package/v2/resources/contacts.d.mts.map +1 -0
  123. package/v2/resources/contacts.d.ts +62 -0
  124. package/v2/resources/contacts.d.ts.map +1 -0
  125. package/v2/resources/contacts.js +66 -0
  126. package/v2/resources/contacts.js.map +1 -0
  127. package/v2/resources/contacts.mjs +62 -0
  128. package/v2/resources/contacts.mjs.map +1 -0
  129. package/v2/resources/conversations.d.mts +51 -0
  130. package/v2/resources/conversations.d.mts.map +1 -0
  131. package/v2/resources/conversations.d.ts +51 -0
  132. package/v2/resources/conversations.d.ts.map +1 -0
  133. package/v2/resources/conversations.js +55 -0
  134. package/v2/resources/conversations.js.map +1 -0
  135. package/v2/resources/conversations.mjs +51 -0
  136. package/v2/resources/conversations.mjs.map +1 -0
  137. package/v2/resources/email-domains.d.mts +72 -0
  138. package/v2/resources/email-domains.d.mts.map +1 -0
  139. package/v2/resources/email-domains.d.ts +72 -0
  140. package/v2/resources/email-domains.d.ts.map +1 -0
  141. package/v2/resources/email-domains.js +80 -0
  142. package/v2/resources/email-domains.js.map +1 -0
  143. package/v2/resources/email-domains.mjs +76 -0
  144. package/v2/resources/email-domains.mjs.map +1 -0
  145. package/v2/resources/functions.d.mts +41 -0
  146. package/v2/resources/functions.d.mts.map +1 -0
  147. package/v2/resources/functions.d.ts +41 -0
  148. package/v2/resources/functions.d.ts.map +1 -0
  149. package/v2/resources/functions.js +41 -0
  150. package/v2/resources/functions.js.map +1 -0
  151. package/v2/resources/functions.mjs +37 -0
  152. package/v2/resources/functions.mjs.map +1 -0
  153. package/v2/resources/index.d.mts +12 -0
  154. package/v2/resources/index.d.mts.map +1 -0
  155. package/v2/resources/index.d.ts +12 -0
  156. package/v2/resources/index.d.ts.map +1 -0
  157. package/v2/resources/index.js +27 -0
  158. package/v2/resources/index.js.map +1 -0
  159. package/v2/resources/index.mjs +13 -0
  160. package/v2/resources/index.mjs.map +1 -0
  161. package/v2/resources/messages.d.mts +82 -0
  162. package/v2/resources/messages.d.mts.map +1 -0
  163. package/v2/resources/messages.d.ts +82 -0
  164. package/v2/resources/messages.d.ts.map +1 -0
  165. package/v2/resources/messages.js +74 -0
  166. package/v2/resources/messages.js.map +1 -0
  167. package/v2/resources/messages.mjs +70 -0
  168. package/v2/resources/messages.mjs.map +1 -0
  169. package/v2/resources/numbers.d.mts +46 -0
  170. package/v2/resources/numbers.d.mts.map +1 -0
  171. package/v2/resources/numbers.d.ts +46 -0
  172. package/v2/resources/numbers.d.ts.map +1 -0
  173. package/v2/resources/numbers.js +41 -0
  174. package/v2/resources/numbers.js.map +1 -0
  175. package/v2/resources/numbers.mjs +37 -0
  176. package/v2/resources/numbers.mjs.map +1 -0
  177. package/v2/resources/templates.d.mts +56 -0
  178. package/v2/resources/templates.d.mts.map +1 -0
  179. package/v2/resources/templates.d.ts +56 -0
  180. package/v2/resources/templates.d.ts.map +1 -0
  181. package/v2/resources/templates.js +61 -0
  182. package/v2/resources/templates.js.map +1 -0
  183. package/v2/resources/templates.mjs +57 -0
  184. package/v2/resources/templates.mjs.map +1 -0
  185. package/v2/resources/webhook.d.mts +67 -0
  186. package/v2/resources/webhook.d.mts.map +1 -0
  187. package/v2/resources/webhook.d.ts +67 -0
  188. package/v2/resources/webhook.d.ts.map +1 -0
  189. package/v2/resources/webhook.js +70 -0
  190. package/v2/resources/webhook.js.map +1 -0
  191. package/v2/resources/webhook.mjs +66 -0
  192. package/v2/resources/webhook.mjs.map +1 -0
  193. package/v2/types.d.mts +2188 -0
  194. package/v2/types.d.mts.map +1 -0
  195. package/v2/types.d.ts +2188 -0
  196. package/v2/types.d.ts.map +1 -0
  197. package/v2/types.js +4 -0
  198. package/v2/types.js.map +1 -0
  199. package/v2/types.mjs +3 -0
  200. package/v2/types.mjs.map +1 -0
  201. package/v2/v2.d.mts +40 -0
  202. package/v2/v2.d.mts.map +1 -0
  203. package/v2/v2.d.ts +40 -0
  204. package/v2/v2.d.ts.map +1 -0
  205. package/v2/v2.js +47 -0
  206. package/v2/v2.js.map +1 -0
  207. package/v2/v2.mjs +42 -0
  208. package/v2/v2.mjs.map +1 -0
  209. package/v2.d.mts +2 -0
  210. package/v2.d.mts.map +1 -0
  211. package/v2.d.ts +2 -0
  212. package/v2.d.ts.map +1 -0
  213. package/v2.js +6 -0
  214. package/v2.js.map +1 -0
  215. package/v2.mjs +3 -0
  216. package/v2.mjs.map +1 -0
  217. package/version.d.mts +1 -1
  218. package/version.d.ts +1 -1
  219. package/version.js +1 -1
  220. package/version.mjs +1 -1
package/v2/types.d.mts ADDED
@@ -0,0 +1,2188 @@
1
+ /**
2
+ * A channel whose connection has an on/off switch. `sms`, `sms_oneway` and `voice`
3
+ * are billed per message and per phone number, are always on, and have nothing to
4
+ * activate.
5
+ */
6
+ export type ActivatableChannel = 'whatsapp' | 'telegram' | 'instagram' | 'messenger' | 'email';
7
+ /**
8
+ * Click-to-WhatsApp (CTWA) ad attribution: where an inbound conversation came
9
+ * from.
10
+ *
11
+ * WhatsApp only. Present on the **first inbound message** of a conversation opened
12
+ * from a Meta ad or post, and on no message after it — so store it when it
13
+ * arrives rather than expecting it again. Organic conversations never carry it.
14
+ *
15
+ * Field names are camelCased to match the rest of this API; Meta sends them as
16
+ * snake_case (`ctwa_clid`, `source_id`, ...). Fields that do not apply are
17
+ * omitted: a `post` source has no click id, and an image ad has no `videoUrl`.
18
+ */
19
+ export interface AdReferral {
20
+ /** Where the click came from. */
21
+ sourceType?: AdReferralSourceType;
22
+ /** Identifier of the ad or post that produced the click. */
23
+ sourceId?: string;
24
+ /** Meta permalink to the ad or post. */
25
+ sourceUrl?: string;
26
+ /** Headline of the ad or post. */
27
+ headline?: string;
28
+ /** Body copy of the ad or post. */
29
+ body?: string;
30
+ /** Type of media on the ad, when it had any. */
31
+ mediaType?: AdReferralMediaType;
32
+ /** Image of the ad. Present when `mediaType` is `image`. */
33
+ imageUrl?: string;
34
+ /** Video of the ad. Present when `mediaType` is `video`. */
35
+ videoUrl?: string;
36
+ /** Thumbnail of the ad media. */
37
+ thumbnailUrl?: string;
38
+ /**
39
+ * Click-to-WhatsApp click identifier. This is the value Meta's Conversions API
40
+ * needs to credit a conversion back to the ad that produced the conversation.
41
+ * Present on `ad` sources; a `post` source has none.
42
+ */
43
+ ctwaClid?: string;
44
+ }
45
+ export type AdReferralSourceType = 'ad' | 'post';
46
+ export type AdReferralMediaType = 'image' | 'video';
47
+ /** An AI agent. It answers on the addresses in `channels`. */
48
+ export interface Agent {
49
+ id: string;
50
+ name: string;
51
+ /** Whether the agent is active. */
52
+ enabled: boolean;
53
+ provider: AgentProvider;
54
+ /** Model ID (e.g., gpt-4o-mini, claude-3-5-sonnet). */
55
+ model: string;
56
+ /** System prompt for the agent. */
57
+ systemPrompt: string;
58
+ /**
59
+ * Number of previous messages to include as context.
60
+ *
61
+ * @defaultValue `10`
62
+ */
63
+ contextWindowMessages?: number;
64
+ /**
65
+ * Whether to include contact metadata in context.
66
+ *
67
+ * @defaultValue `true`
68
+ */
69
+ includeContactMetadata?: boolean;
70
+ /** Maximum tokens for LLM response. */
71
+ maxTokens?: number | null;
72
+ /** LLM temperature (0-2). */
73
+ temperature?: number | null;
74
+ /** Channels that trigger the agent. */
75
+ triggerOnChannels?: Array<string>;
76
+ /** Message types that trigger the agent. */
77
+ triggerOnMessageTypes?: Array<string>;
78
+ stats?: AgentStats;
79
+ createdAt: string;
80
+ updatedAt: string;
81
+ /**
82
+ * Voice Agent configuration. When present and enabled, the agent can answer
83
+ * inbound phone calls and place outbound calls with Zavu's managed voice pipeline.
84
+ * Requires the Voice Agents feature to be enabled for your team.
85
+ */
86
+ voice?: AgentVoiceConfig;
87
+ /**
88
+ * The (address, type) entries this agent answers on: every transport of the
89
+ * addresses it is connected to that its `triggerOnChannels` allows. Connect one
90
+ * with `POST /v2/agents/{agentId}/channels`.
91
+ */
92
+ channels: Array<AgentChannelsItem>;
93
+ }
94
+ export interface AgentStats {
95
+ totalInvocations?: number;
96
+ totalTokensUsed?: number;
97
+ /** Total cost in USD. */
98
+ totalCost?: number;
99
+ }
100
+ export interface AgentChannelsItem {
101
+ address: string;
102
+ type: ChannelType;
103
+ active: boolean;
104
+ }
105
+ /** Create an agent that exists on its own, disabled and connected to no channel. */
106
+ export interface AgentCreateStandaloneRequest {
107
+ name: string;
108
+ provider: AgentProvider;
109
+ /**
110
+ * Your key for the model provider. Required for `openai`, `anthropic`, `google`
111
+ * and `mistral`, where a request without it is refused with `400`; not used with
112
+ * `zavu`. Stored encrypted and never returned.
113
+ */
114
+ apiKey?: string;
115
+ model: string;
116
+ systemPrompt: string;
117
+ /** @defaultValue `10` */
118
+ contextWindowMessages?: number;
119
+ /** @defaultValue `true` */
120
+ includeContactMetadata?: boolean;
121
+ /** @defaultValue `["*"]` */
122
+ triggerOnChannels?: Array<string>;
123
+ /** @defaultValue `["text"]` */
124
+ triggerOnMessageTypes?: Array<string>;
125
+ maxTokens?: number;
126
+ temperature?: number;
127
+ voice?: AgentVoiceConfig;
128
+ }
129
+ /** LLM provider for the AI agent. */
130
+ export type AgentProvider = 'openai' | 'anthropic' | 'google' | 'mistral' | 'zavu';
131
+ /**
132
+ * Run the agent and return what it would say. Nothing is delivered to anyone and
133
+ * no execution is recorded.
134
+ *
135
+ * A run is **billed like a live reply**: on an agent with the `zavu` provider it
136
+ * is charged to your balance at the same price per token, and refused with `402
137
+ * insufficient_balance` at a balance of zero. On a bring-your-own-key agent it
138
+ * costs your provider, not Zavu. `cost` on the response is what this run charged.
139
+ */
140
+ export interface AgentTestRequest {
141
+ /** What to say to the agent. */
142
+ message: string;
143
+ /**
144
+ * Prior turns, oldest first, to exercise multi-turn behaviour without persisting a
145
+ * thread. Trimmed to the agent's context window.
146
+ */
147
+ history?: Array<AgentTestRequestHistoryItem>;
148
+ /**
149
+ * Set false to skip retrieval and isolate prompt behaviour from the knowledge
150
+ * base.
151
+ *
152
+ * @defaultValue `true`
153
+ */
154
+ useKnowledgeBase?: boolean;
155
+ /**
156
+ * Run the tools the agent calls instead of reporting the choice and stopping.
157
+ *
158
+ * Off by default because a tool handler talks to the outside world: a rehearsal
159
+ * that charges a card is not a rehearsal. Turn it on to exercise the loop that
160
+ * actually matters — the model picks a tool, the handler answers, the model
161
+ * replies with the result — without sending a message to anyone. What ran comes
162
+ * back in `executedToolCalls`.
163
+ *
164
+ * @defaultValue `false`
165
+ */
166
+ executeTools?: boolean;
167
+ }
168
+ export interface AgentTestRequestHistoryItem {
169
+ role: AgentTestRequestHistoryItemRole;
170
+ content: string;
171
+ }
172
+ export type AgentTestRequestHistoryItemRole = 'user' | 'assistant';
173
+ export interface AgentTestResponse {
174
+ success: boolean;
175
+ /** What the agent would reply. */
176
+ text: string | null;
177
+ error: string | null;
178
+ inputTokens: number;
179
+ outputTokens: number;
180
+ latencyMs: number;
181
+ /**
182
+ * Knowledge-base chunks retrieved for this message. Zero means the answer was not
183
+ * grounded in your documents.
184
+ */
185
+ knowledgeChunksUsed: number;
186
+ /**
187
+ * Tools that actually ran, in order, when the request set `executeTools`. Empty on
188
+ * a normal dry run, where nothing is executed. An entry with `ok: false` means the
189
+ * agent saw an error and answered around it, which is what a customer would have
190
+ * received.
191
+ */
192
+ executedToolCalls?: Array<AgentTestResponseExecutedToolCallsItem>;
193
+ /**
194
+ * Things that are true of this agent but that a dry run cannot prove. Surfaced so
195
+ * a passing dry run is never mistaken for proof that the agent works live.
196
+ *
197
+ * - The agent being disabled.
198
+ * - Enabled tools that were offered to the model but not run: if the agent picks
199
+ * one, the reply stops at that choice (see `plannedToolCalls`). Pass
200
+ * `executeTools` to run them.
201
+ * - Tools that ran for real, when `executeTools` was set, and any that failed.
202
+ * - An agent whose sender has none of the channels it triggers on, which answers
203
+ * every dry run and no real message.
204
+ * - Contact metadata that exists on a real conversation but not here, and memory
205
+ * tools (`remember`, `recall`, `save_record`), which have no contact to write
206
+ * about on a test run.
207
+ */
208
+ warnings: Array<string>;
209
+ /**
210
+ * USD charged to your balance for this run, rounded to 6 decimals. 0 on a
211
+ * bring-your-own-key agent. When the balance covers only part of a run, that part
212
+ * is charged and the next run is refused with `402`.
213
+ */
214
+ cost: number;
215
+ /**
216
+ * Tools the model chose to call, with the arguments it chose, on a run without
217
+ * `executeTools`. Nothing was executed: the reply stops at the choice. Empty when
218
+ * it answered without reaching for a tool, and on a run that executed tools (see
219
+ * `executedToolCalls`).
220
+ */
221
+ plannedToolCalls: Array<AgentTestResponsePlannedToolCallsItem>;
222
+ }
223
+ export interface AgentTestResponseExecutedToolCallsItem {
224
+ name: string;
225
+ ok: boolean;
226
+ error?: string | null;
227
+ }
228
+ export interface AgentTestResponsePlannedToolCallsItem {
229
+ name: string;
230
+ /** The arguments as a JSON string. */
231
+ arguments: string;
232
+ }
233
+ export interface AgentUpdateRequest {
234
+ name?: string;
235
+ enabled?: boolean;
236
+ provider?: AgentProvider;
237
+ model?: string;
238
+ systemPrompt?: string;
239
+ apiKey?: string;
240
+ contextWindowMessages?: number;
241
+ includeContactMetadata?: boolean;
242
+ maxTokens?: number | null;
243
+ temperature?: number | null;
244
+ triggerOnChannels?: Array<string>;
245
+ triggerOnMessageTypes?: Array<string>;
246
+ /**
247
+ * Voice Agent configuration. Patch this object to enable voice, change the
248
+ * greeting, or adjust call limits. Requires the Voice Agents feature to be enabled
249
+ * for your team.
250
+ */
251
+ voice?: AgentVoiceConfig;
252
+ }
253
+ /**
254
+ * Voice Agent configuration on an AI agent. Controls how the agent behaves on
255
+ * inbound and outbound phone calls through Zavu's managed voice pipeline (speech
256
+ * recognition, the agent's LLM, and speech synthesis, with real-time interruption
257
+ * handling). Requires the Voice Agents feature to be enabled for your team.
258
+ */
259
+ export interface AgentVoiceConfig {
260
+ /**
261
+ * Whether the agent handles voice calls. When false, the voice agent does not
262
+ * answer calls and outbound calls are rejected.
263
+ */
264
+ enabled: boolean;
265
+ /**
266
+ * Opening line the agent speaks when the call connects. If omitted, the agent
267
+ * waits for the caller to speak first.
268
+ */
269
+ greeting?: string;
270
+ /**
271
+ * Greeting per language, keyed by language code. Used when the caller's language
272
+ * differs from the one `greeting` is written in.
273
+ */
274
+ greetings?: {
275
+ [key: string]: string;
276
+ };
277
+ /**
278
+ * BCP-47 language code used for both speech recognition and speech synthesis (e.g.
279
+ * `en`, `es`, `pt-BR`). Auto-detected from the recipient when omitted.
280
+ */
281
+ language?: string;
282
+ /**
283
+ * Model that runs the conversation, co-located in the voice network for lowest
284
+ * latency. Independent of the model used for text messaging. Derived from the
285
+ * agent's text model when omitted.
286
+ */
287
+ model?: string;
288
+ /** Speech-recognition provider. Uses the default when omitted. */
289
+ sttProvider?: string;
290
+ /** Speech-recognition model. Uses the default when omitted. */
291
+ sttModel?: string;
292
+ /** Speech-synthesis provider. Uses the default when omitted. */
293
+ ttsProvider?: string;
294
+ /**
295
+ * Identifier of the synthesized voice that speaks. Choose from the voices
296
+ * available in the dashboard. Uses a neutral default when omitted.
297
+ */
298
+ ttsVoiceId?: string;
299
+ /**
300
+ * Speech rate. 1.0 is natural. Only honoured by voices that support rate control;
301
+ * ignored by the others.
302
+ *
303
+ * @defaultValue `1.0`
304
+ */
305
+ voiceSpeed?: number;
306
+ /**
307
+ * Whether the caller can interrupt the agent while it is speaking (barge-in). When
308
+ * true, the agent stops talking as soon as the caller starts.
309
+ *
310
+ * @defaultValue `true`
311
+ */
312
+ interruptible?: boolean;
313
+ /**
314
+ * Hard limit on call length in minutes. The call ends automatically when reached.
315
+ *
316
+ * @defaultValue `15`
317
+ */
318
+ maxCallDurationMinutes?: number;
319
+ /**
320
+ * How long the agent waits during silence before ending the call.
321
+ *
322
+ * @defaultValue `30`
323
+ */
324
+ maxIdleSeconds?: number;
325
+ /** Whether the call audio is recorded. */
326
+ recordCalls?: boolean;
327
+ /**
328
+ * What the agent does when an answering machine or voicemail is detected on an
329
+ * outbound call.
330
+ *
331
+ * @defaultValue `"hangup"`
332
+ */
333
+ voicemailAction?: AgentVoiceConfigVoicemailAction;
334
+ /**
335
+ * Message spoken when `voicemailAction` is `leave_message`. Falls back to
336
+ * `greeting` when omitted.
337
+ */
338
+ voicemailMessage?: string;
339
+ /**
340
+ * E.164 phone number the agent can transfer the call to. When set, the agent is
341
+ * given a transfer tool it can use to hand the call to a human.
342
+ */
343
+ transferPhoneNumber?: string;
344
+ }
345
+ export type AgentVoiceConfigVoicemailAction = 'hangup' | 'leave_message';
346
+ export interface AvailablePhoneNumber {
347
+ phoneNumber: string;
348
+ friendlyName?: string;
349
+ locality?: string;
350
+ region?: string;
351
+ capabilities: PhoneNumberCapabilities;
352
+ pricing: PhoneNumberPricing;
353
+ }
354
+ /**
355
+ * A campaign. The same object as a /v1 broadcast: its `id` works on
356
+ * `/v1/broadcasts/{broadcastId}`.
357
+ */
358
+ export interface Broadcast {
359
+ id: string;
360
+ name: string;
361
+ status: BroadcastStatus;
362
+ channel: BroadcastChannel;
363
+ messageType: BroadcastMessageType;
364
+ text?: string;
365
+ content?: BroadcastContent;
366
+ emailSubject?: string;
367
+ /** Total number of contacts in the broadcast. */
368
+ totalContacts: number;
369
+ pendingCount?: number;
370
+ sendingCount?: number;
371
+ /**
372
+ * Recipients whose message the provider accepted, without a confirmed delivery
373
+ * yet. Channels that never report delivery keep their recipients here.
374
+ */
375
+ sentCount?: number;
376
+ /** Recipients with confirmed delivery to the device. */
377
+ deliveredCount?: number;
378
+ failedCount?: number;
379
+ /** Estimated total cost in USD. */
380
+ estimatedCost?: number | null;
381
+ /** Amount reserved from balance in USD. */
382
+ reservedAmount?: number | null;
383
+ /** Actual cost so far in USD. */
384
+ actualCost?: number | null;
385
+ scheduledAt?: string;
386
+ startedAt?: string;
387
+ completedAt?: string;
388
+ metadata?: {
389
+ [key: string]: string;
390
+ };
391
+ createdAt: string;
392
+ updatedAt?: string;
393
+ /** AI content review result. */
394
+ reviewResult?: BroadcastReviewResult | null;
395
+ /** Number of review attempts (max 3). */
396
+ reviewAttempts?: number | null;
397
+ /**
398
+ * The address the campaign is sent from, for its `channel` (the sender's first
399
+ * address when `channel` is `smart`).
400
+ */
401
+ from?: string | null;
402
+ }
403
+ export interface BroadcastReviewResult {
404
+ /** Content safety score from 0.0 to 1.0, where 1.0 is completely safe. */
405
+ score?: number;
406
+ /** Policy categories violated, if any. */
407
+ categories?: Array<string>;
408
+ /** Explanation of the review decision. */
409
+ reasoning?: string;
410
+ reviewedAt?: string;
411
+ /** Problematic text fragments, if any. */
412
+ flaggedContent?: Array<string> | null;
413
+ }
414
+ /** Broadcast delivery channel. Use 'smart' for per-contact intelligent routing. */
415
+ export type BroadcastChannel = 'smart' | 'sms' | 'sms_oneway' | 'whatsapp' | 'telegram' | 'email';
416
+ export interface BroadcastContactInput {
417
+ /**
418
+ * Phone number (E.164) or email address. On a `telegram` broadcast, the numeric
419
+ * chat ID of someone who has already written to your bot (`838360395`, or
420
+ * `telegram:838360395`); a phone number is rejected there, because a bot cannot
421
+ * start a chat.
422
+ */
423
+ recipient: string;
424
+ /**
425
+ * Per-contact body variables. Key them to match the template body: by position
426
+ * (`1`, `2`, ...) for positional templates, or by name (e.g. `customer_name`) for
427
+ * named templates. Zavu detects the template's format and sends the correct
428
+ * payload to Meta. Do not mix positional and named keys.
429
+ */
430
+ templateVariables?: {
431
+ [key: string]: string;
432
+ };
433
+ /**
434
+ * Per-contact button variables for dynamic URL/OTP buttons. Keys are the button
435
+ * index (0, 1, 2).
436
+ */
437
+ templateButtonVariables?: {
438
+ [key: string]: string;
439
+ };
440
+ /**
441
+ * Per-contact value for a text-header variable, keyed by `1`. If omitted, Zavu
442
+ * resolves the header from `templateVariables` by the header placeholder's name.
443
+ */
444
+ templateHeaderVariables?: {
445
+ [key: string]: string;
446
+ };
447
+ }
448
+ export interface BroadcastContactsAddRequest {
449
+ /** List of contacts to add (max 1000 per request). */
450
+ contacts: Array<BroadcastContactInput>;
451
+ }
452
+ export interface BroadcastContactsAddResponse {
453
+ /** Number of contacts successfully added. */
454
+ added: number;
455
+ /** Number of duplicate contacts skipped. */
456
+ duplicates: number;
457
+ /** Number of invalid contacts rejected. */
458
+ invalid: number;
459
+ /** Details about invalid contacts. */
460
+ errors?: Array<BroadcastContactsAddResponseErrorsItem>;
461
+ }
462
+ export interface BroadcastContactsAddResponseErrorsItem {
463
+ recipient?: string;
464
+ /**
465
+ * Why it was not added, in words that are true of this recipient and this
466
+ * campaign.
467
+ */
468
+ reason?: string;
469
+ /**
470
+ * Set for `unreachable_by_channel` and `ten_dlc_required`. Absent on other
471
+ * reasons.
472
+ */
473
+ code?: BroadcastContactsAddResponseErrorsItemCode;
474
+ }
475
+ export type BroadcastContactsAddResponseErrorsItemCode = 'unreachable_by_channel' | 'ten_dlc_required';
476
+ /** Content for non-text broadcast message types. */
477
+ export interface BroadcastContent {
478
+ /** URL of the media file. */
479
+ mediaUrl?: string;
480
+ /** Media ID if already uploaded. */
481
+ mediaId?: string;
482
+ /** MIME type of the media. */
483
+ mimeType?: string;
484
+ /** Filename for documents. */
485
+ filename?: string;
486
+ /** Template ID for template messages. */
487
+ templateId?: string;
488
+ /**
489
+ * Default body variables (can be overridden per contact). Key them to match the
490
+ * template body: by position (`1`, `2`, ...) for positional templates, or by name
491
+ * (e.g. `customer_name`) for named templates. Zavu detects the template's format
492
+ * and sends the correct payload to Meta. Do not mix positional and named keys.
493
+ */
494
+ templateVariables?: {
495
+ [key: string]: string;
496
+ };
497
+ /**
498
+ * Default button variables for dynamic URL/OTP buttons. Keys are the button index
499
+ * (0, 1, 2). Per-contact values override these.
500
+ */
501
+ templateButtonVariables?: {
502
+ [key: string]: string;
503
+ };
504
+ /**
505
+ * Default value for a text-header variable, keyed by `1` (can be overridden per
506
+ * contact). If omitted, Zavu resolves the header from `templateVariables` by the
507
+ * header placeholder's name.
508
+ */
509
+ templateHeaderVariables?: {
510
+ [key: string]: string;
511
+ };
512
+ }
513
+ /** A campaign is a /v1 broadcast. Create it, add recipients, then send. */
514
+ export interface BroadcastCreateRequest {
515
+ /** Name of the broadcast campaign. */
516
+ name: string;
517
+ channel: BroadcastChannel;
518
+ /** @defaultValue `"text"` */
519
+ messageType?: BroadcastMessageType;
520
+ /** Text content or caption. Supports template variables: {{name}}, {{1}}, etc. */
521
+ text?: string;
522
+ content?: BroadcastContent;
523
+ /** Email subject line. Required for email broadcasts. */
524
+ emailSubject?: string;
525
+ /** HTML body for email broadcasts. */
526
+ emailHtmlBody?: string;
527
+ /** Schedule the broadcast for future delivery. */
528
+ scheduledAt?: string;
529
+ metadata?: {
530
+ [key: string]: string;
531
+ };
532
+ /** Idempotency key to prevent duplicate broadcasts. */
533
+ idempotencyKey?: string;
534
+ /**
535
+ * The address that sends the campaign (`GET /v2/channels`). The project default
536
+ * when omitted. Resolved like `from` on `POST /v2/messages`, with the campaign's
537
+ * `channel` as the transport (none for `smart`).
538
+ */
539
+ from?: string;
540
+ }
541
+ /** Type of message for broadcast. */
542
+ export type BroadcastMessageType = 'text' | 'image' | 'video' | 'audio' | 'document' | 'template';
543
+ export interface BroadcastProgress {
544
+ status: BroadcastStatus;
545
+ /** Total contacts in broadcast. */
546
+ total: number;
547
+ /** Not yet queued for sending. */
548
+ pending: number;
549
+ /** Currently being sent. */
550
+ sending: number;
551
+ /** Accepted by the provider, delivery not confirmed yet. */
552
+ sent?: number;
553
+ /** Confirmed delivered to the device. */
554
+ delivered: number;
555
+ /** Failed to deliver. */
556
+ failed: number;
557
+ /** Skipped (broadcast cancelled). */
558
+ skipped: number;
559
+ /** Percentage complete (0-100). */
560
+ percentComplete: number;
561
+ /** Estimated total cost in USD. */
562
+ estimatedCost?: number | null;
563
+ /** Amount reserved from balance in USD. */
564
+ reservedAmount?: number | null;
565
+ /** Actual cost so far in USD. */
566
+ actualCost?: number | null;
567
+ startedAt?: string;
568
+ estimatedCompletionAt?: string;
569
+ campaignId: string;
570
+ }
571
+ export interface BroadcastSendRequest {
572
+ /** Schedule for future delivery. Omit to send immediately. */
573
+ scheduledAt?: string;
574
+ }
575
+ /**
576
+ * Current status of the campaign. `pending_review`: in the automated content
577
+ * review. `pending_admin_review`: the automated review passed and it waits for a
578
+ * person, which is where every channel but a WhatsApp campaign on an approved
579
+ * template goes. `rejected`: the review refused it; edit it and send again, or
580
+ * escalate. `scheduled` and `sending` follow approval.
581
+ */
582
+ export type BroadcastStatus = 'draft' | 'pending_review' | 'pending_admin_review' | 'approved' | 'rejected' | 'escalated' | 'rejected_final' | 'scheduled' | 'sending' | 'paused' | 'completed' | 'cancelled' | 'failed';
583
+ /** A transport a message travels on. */
584
+ export type ChannelType = 'sms' | 'sms_oneway' | 'whatsapp' | 'telegram' | 'email' | 'instagram' | 'messenger' | 'voice';
585
+ /**
586
+ * `auto`, or a transport. `auto` applies the fixed order described on `POST
587
+ * /v2/messages`.
588
+ */
589
+ export type ChannelTypeRequest = 'auto' | 'sms' | 'sms_oneway' | 'whatsapp' | 'telegram' | 'email' | 'instagram' | 'messenger' | 'voice';
590
+ export interface Contact {
591
+ id: string;
592
+ /** Display name for the contact. */
593
+ displayName?: string;
594
+ /** DEPRECATED: Use primaryPhone instead. Primary phone number in E.164 format. */
595
+ phoneNumber?: string;
596
+ /** Primary phone number in E.164 format. */
597
+ primaryPhone?: string;
598
+ /** Primary email address. */
599
+ primaryEmail?: string;
600
+ countryCode?: string;
601
+ /** Contact's WhatsApp profile name. Only available for WhatsApp contacts. */
602
+ profileName?: string | null;
603
+ /** List of available messaging channels for this contact. */
604
+ availableChannels: Array<string>;
605
+ /** Preferred channel for this contact. */
606
+ defaultChannel?: ContactDefaultChannel;
607
+ /** Whether this contact has been verified. */
608
+ verified: boolean;
609
+ /** All communication channels for this contact. */
610
+ channels?: Array<ContactChannel>;
611
+ metadata: {
612
+ [key: string]: string;
613
+ };
614
+ createdAt: string;
615
+ updatedAt?: string;
616
+ }
617
+ export type ContactDefaultChannel = 'sms' | 'whatsapp' | 'telegram' | 'email' | 'instagram' | 'messenger' | 'voice';
618
+ /** A communication channel for a contact. */
619
+ export interface ContactChannel {
620
+ id: string;
621
+ /** Channel type. */
622
+ channel: ContactChannelChannel;
623
+ /** Channel identifier (phone number or email address). */
624
+ identifier: string;
625
+ /** ISO country code for phone numbers. */
626
+ countryCode?: string;
627
+ /** Optional label for the channel. */
628
+ label?: string;
629
+ /** Whether this is the primary channel for its type. */
630
+ isPrimary: boolean;
631
+ /** Whether this channel has been verified. */
632
+ verified: boolean;
633
+ /** Delivery metrics for this channel. */
634
+ metrics?: ContactChannelMetrics;
635
+ /** Last time a message was received on this channel. */
636
+ lastInboundAt?: string;
637
+ metadata?: {
638
+ [key: string]: string;
639
+ };
640
+ createdAt: string;
641
+ updatedAt?: string;
642
+ }
643
+ export type ContactChannelChannel = 'sms' | 'whatsapp' | 'email' | 'telegram' | 'instagram' | 'messenger' | 'voice';
644
+ export interface ContactChannelMetrics {
645
+ successCount?: number;
646
+ failureCount?: number;
647
+ totalAttempts?: number;
648
+ avgDeliveryTimeMs?: number;
649
+ lastSuccessAt?: string;
650
+ }
651
+ /** Input for creating a contact channel. */
652
+ export interface ContactChannelInput {
653
+ /** Channel type. */
654
+ channel: ContactChannelInputChannel;
655
+ /** Channel identifier (phone number in E.164 format or email address). */
656
+ identifier: string;
657
+ /** ISO country code for phone numbers. */
658
+ countryCode?: string;
659
+ /** Optional label for the channel. */
660
+ label?: string;
661
+ /**
662
+ * Whether this should be the primary channel for its type.
663
+ *
664
+ * @defaultValue `false`
665
+ */
666
+ isPrimary?: boolean;
667
+ }
668
+ export type ContactChannelInputChannel = 'sms' | 'whatsapp' | 'email' | 'telegram' | 'instagram' | 'messenger' | 'voice';
669
+ /** Request body to create a contact with channels. */
670
+ export interface ContactCreateRequest {
671
+ /** Display name for the contact. */
672
+ displayName?: string;
673
+ /** Communication channels for the contact. */
674
+ channels: Array<ContactChannelInput>;
675
+ /** Arbitrary metadata to associate with the contact. */
676
+ metadata?: {
677
+ [key: string]: string;
678
+ };
679
+ }
680
+ export interface ContactUpdateRequest {
681
+ /**
682
+ * Human-readable name for this contact. Set to null to clear it and fall back to
683
+ * the contact's identifier. Contacts created automatically from an inbound message
684
+ * have no display name until you set one.
685
+ */
686
+ displayName?: string | null;
687
+ /** Preferred channel for this contact. Set to null to clear. */
688
+ defaultChannel?: ContactUpdateRequestDefaultChannel | null;
689
+ metadata?: {
690
+ [key: string]: string;
691
+ };
692
+ }
693
+ export type ContactUpdateRequestDefaultChannel = 'sms' | 'whatsapp' | 'telegram' | 'email' | 'instagram' | 'messenger' | 'voice';
694
+ /**
695
+ * An inbox thread with one contact. A conversation groups every message exchanged
696
+ * with that contact across channels, so a contact who writes on WhatsApp and later
697
+ * by email stays in one thread.
698
+ */
699
+ export interface Conversation {
700
+ id: string;
701
+ /**
702
+ * ID of the contact this thread belongs to. Absent on group threads and on threads
703
+ * whose contact has not been resolved yet.
704
+ */
705
+ contactId?: string;
706
+ /**
707
+ * The key this thread is filed under: a phone number in E.164, a WhatsApp
708
+ * business-scoped user ID (BSUID), or a numeric chat ID
709
+ * (Telegram/Instagram/Messenger). It is not always a phone number, so do not parse
710
+ * it as one.
711
+ */
712
+ contactIdentifier: string;
713
+ /** Email address of the thread, when the contact was reached by email. */
714
+ email?: string;
715
+ /** Every channel this thread has carried messages on. */
716
+ channels: Array<string>;
717
+ /**
718
+ * Denormalized preview of the most recent message, so a thread list needs no extra
719
+ * fetch.
720
+ */
721
+ lastMessage: ConversationLastMessage;
722
+ messageCount: number;
723
+ /**
724
+ * Inbound messages not yet marked read. Reset with POST
725
+ * /v2/conversations/{conversationId}/read.
726
+ */
727
+ unreadCount: number;
728
+ /** WhatsApp identity, present when the contact adopted a username. */
729
+ whatsapp?: ConversationWhatsapp;
730
+ createdAt: string;
731
+ updatedAt: string;
732
+ /**
733
+ * The address this thread was last handled from, on the transport of its last
734
+ * message. Pass the conversation's `id` as `conversationId` on `POST /v2/messages`
735
+ * to reply from it. A thread opened by an API send before /v2 recorded no sender;
736
+ * its `from` is read off its messages. `?from=` on the list matches threads by the
737
+ * recorded sender only, which messages sent through /v2 record.
738
+ */
739
+ from?: string | null;
740
+ }
741
+ export interface ConversationLastMessage {
742
+ id: string;
743
+ /** Text or caption. Empty when the last message carried no text (e.g. media). */
744
+ text: string;
745
+ channel: ChannelType;
746
+ direction: ConversationLastMessageDirection;
747
+ at: string;
748
+ }
749
+ export type ConversationLastMessageDirection = 'inbound' | 'outbound';
750
+ export interface ConversationWhatsapp {
751
+ /** Business-scoped user ID. Can be used as `to` when sending. */
752
+ bsuid?: string;
753
+ username?: string;
754
+ }
755
+ /** Email attachment. Provide either `content` (base64) or `path` (URL), not both. */
756
+ export interface EmailAttachmentInput {
757
+ /** Name of the attached file. */
758
+ filename: string;
759
+ /** Content of the attached file as a Base64-encoded string. */
760
+ content?: string;
761
+ /** URL where the attachment file is hosted. The server will fetch the file. */
762
+ path?: string;
763
+ /** MIME type of the attachment. If not set, will be derived from the filename. */
764
+ content_type?: string;
765
+ /**
766
+ * Content ID for inline images. Reference in HTML as `<img
767
+ * src="cid:your_content_id">`.
768
+ */
769
+ content_id?: string;
770
+ }
771
+ /**
772
+ * Every v2 error has this shape at the root. There is no `{error: {...}}` wrapper
773
+ * anywhere in v2. A missing resource is `404 not_found` with the message
774
+ * `<Resource> not found`; an address the project does not have is `404 not_found`,
775
+ * `None of this project's channels has the address <address>.`, with the address
776
+ * in `details` under the name the request used (`from` or `address`). A `message`
777
+ * is written for the caller and never carries a stack trace or a source path. A
778
+ * body that is not JSON is `400 invalid_json`, with `details.errors` (`path: []`,
779
+ * the parse error in `message`).
780
+ */
781
+ export interface ErrorBody {
782
+ code: string;
783
+ message: string;
784
+ /**
785
+ * Machine-readable context. Keys that mean the same thing everywhere:
786
+ * - `errors`: present on every `400 invalid_request` for an invalid body or query
787
+ * parameter, `[{path, message, ...}]`, `path` naming the field (`["to"]`,
788
+ * `["contacts", 2, "recipient"]`, `["limit"]`).
789
+ * - `recommendation`: one sentence saying what to do next.
790
+ * - `dashboardUrl`: the dashboard screen that fixes it.
791
+ * - `connect`: on `409 no_channel`, the channels this project can connect to reach
792
+ * the recipient, each `{type, request, note, available, dashboardUrl?}`;
793
+ * `request` is the exact call (`POST /v2/channels` with its body, or `POST
794
+ * /v2/numbers`), or null for a channel connected from the dashboard (WhatsApp,
795
+ * Instagram, Messenger). `available: false` says why in `note` (one-way SMS
796
+ * closed until business verification is approved).
797
+ * - `address` / `from`: the address the error is about, under the name the request
798
+ * used for it.
799
+ */
800
+ details?: ErrorDetails;
801
+ }
802
+ export interface ErrorDetails {
803
+ errors?: Array<ErrorDetailsErrorsItem>;
804
+ [key: string]: unknown;
805
+ }
806
+ export interface ErrorDetailsErrorsItem {
807
+ path: Array<ErrorDetailsErrorsItemPathItem>;
808
+ message: string;
809
+ code?: string;
810
+ [key: string]: unknown;
811
+ }
812
+ export type ErrorDetailsErrorsItemPathItem = string | number;
813
+ export interface Message {
814
+ id: string;
815
+ to: string;
816
+ /**
817
+ * Where the message came from: for an outbound message, your address (as `GET
818
+ * /v2/channels` lists it for `channel`, except WhatsApp, where it is the sender's
819
+ * own number field); for an inbound one, the contact.
820
+ */
821
+ from?: string;
822
+ channel: ChannelType;
823
+ /**
824
+ * Who sent the message. Needed to render a thread: `status` cannot tell the two
825
+ * apart, because an inbound message is also stored as `delivered`.
826
+ */
827
+ direction: MessageDirection;
828
+ messageType: MessageType;
829
+ status: MessageStatus;
830
+ /** Text content or caption. */
831
+ text?: string;
832
+ content?: MessageContent;
833
+ /**
834
+ * ID of the conversation (inbox thread) this message belongs to. Use it to build a
835
+ * direct dashboard link:
836
+ * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`. Omitted only
837
+ * on legacy messages created before conversation threading.
838
+ */
839
+ conversationId?: string;
840
+ /** Message ID from the delivery provider. */
841
+ providerMessageId?: string;
842
+ /**
843
+ * Why a failed message failed, as a Zavu code: `RISK_REJECTED`,
844
+ * `DAILY_LIMIT_EXCEEDED`, `TEN_DLC_REQUIRED`, `SMS_NOT_DELIVERED`,
845
+ * `WHATSAPP_WINDOW_CLOSED`... A delivery provider's own code is translated where
846
+ * its meaning is known and kept in `errorDetails.providerCode`; one with no known
847
+ * meaning is `SMS_DELIVERY_FAILED`, `WHATSAPP_REJECTED`, `VOICE_DELIVERY_FAILED`,
848
+ * `EMAIL_DELIVERY_FAILED` or `DELIVERY_FAILED`. (/v1 returns the provider's raw
849
+ * code here.)
850
+ */
851
+ errorCode?: string | null;
852
+ errorMessage?: string | null;
853
+ /**
854
+ * Zavu's own per-message platform charge, in USD (6 decimals). Messaging is billed
855
+ * against the plan's allowance, so it is often 0.
856
+ */
857
+ cost?: number | null;
858
+ /**
859
+ * What delivering the message cost Zavu (carrier cost), in USD. Filled in when the
860
+ * delivery report brings it, so null until then.
861
+ */
862
+ costProvider?: number | null;
863
+ /**
864
+ * `cost` + `costProvider`. For SMS this is BEFORE Zavu's markup, so it is not what
865
+ * your balance was charged: read `charged` for that. For voice it includes the
866
+ * markup.
867
+ */
868
+ costTotal?: number | null;
869
+ metadata?: {
870
+ [key: string]: string;
871
+ };
872
+ createdAt: string;
873
+ updatedAt?: string;
874
+ /**
875
+ * Transports tried before the current `channel`, oldest first, when an automatic
876
+ * fallback moved the message (WhatsApp to SMS). Empty when no fallback happened.
877
+ * Fallback runs after the send returned, so this can change after `POST
878
+ * /v2/messages` answered.
879
+ */
880
+ attemptedChannels?: Array<ChannelType>;
881
+ /**
882
+ * `held` while the message waits for risk review (it stays `queued`), `released`
883
+ * once a reviewer let it go, null when it was never held.
884
+ */
885
+ riskHold?: MessageRiskHold | null;
886
+ /** Present when `errorCode` translates a delivery provider's code. */
887
+ errorDetails?: MessageErrorDetails | null;
888
+ /**
889
+ * What this message has taken from your prepaid balance, in USD. SMS and one-way
890
+ * SMS only: charged per segment when the message is accepted
891
+ * (`routing.estimatedCost`), raised if the delivery report brings a higher real
892
+ * cost, and refunded (0) when the message fails AND the carrier charged nothing. A
893
+ * failed SMS the carrier did charge for (it attempted delivery) stays charged.
894
+ * Null on other channels, which are not billed per message here.
895
+ */
896
+ charged?: number | null;
897
+ }
898
+ export type MessageDirection = 'inbound' | 'outbound';
899
+ export type MessageRiskHold = 'held' | 'released';
900
+ export interface MessageErrorDetails {
901
+ /** The provider's own code, unchanged. */
902
+ providerCode?: string;
903
+ }
904
+ /** Content for non-text message types (WhatsApp and Telegram). */
905
+ export interface MessageContent {
906
+ /** URL of the media file (for image, video, audio, document, sticker). */
907
+ mediaUrl?: string;
908
+ /** WhatsApp media ID if already uploaded. */
909
+ mediaId?: string;
910
+ /** MIME type of the media. */
911
+ mimeType?: string;
912
+ /** Filename for documents. */
913
+ filename?: string;
914
+ /** Latitude for location messages. */
915
+ latitude?: number;
916
+ /** Longitude for location messages. */
917
+ longitude?: number;
918
+ /** Name of the location. */
919
+ locationName?: string;
920
+ /** Address of the location. */
921
+ locationAddress?: string;
922
+ /** Contact cards for contact messages. */
923
+ contacts?: Array<MessageContentContactsItem>;
924
+ /** Interactive buttons (max 3). */
925
+ buttons?: Array<MessageContentButtonsItem>;
926
+ /** Button text for list messages. */
927
+ listButton?: string;
928
+ /** Sections for list messages. */
929
+ sections?: Array<MessageContentSectionsItem>;
930
+ /** Button label for cta_url messages. */
931
+ ctaDisplayText?: string;
932
+ /**
933
+ * Destination URL opened in the device's default browser when the button is
934
+ * tapped. Used with messageType=cta_url. WhatsApp requires HTTPS in production.
935
+ */
936
+ ctaUrl?: string;
937
+ /** Optional header type for cta_url messages. */
938
+ ctaHeaderType?: MessageContentCtaHeaderType;
939
+ /** Header text when ctaHeaderType is 'text'. */
940
+ ctaHeaderText?: string;
941
+ /**
942
+ * Public HTTPS URL of the header media when ctaHeaderType is 'image', 'video', or
943
+ * 'document'. WhatsApp fetches this URL — it must be publicly reachable and
944
+ * return the declared content type.
945
+ */
946
+ ctaHeaderMediaUrl?: string;
947
+ /** Optional footer text for cta_url messages. */
948
+ footerText?: string;
949
+ /** Emoji for reaction messages. */
950
+ emoji?: string;
951
+ /** Message ID to react to. */
952
+ reactToMessageId?: string;
953
+ /**
954
+ * Zavu message ID of the quoted message this message replies to.
955
+ *
956
+ * **When sending:** set it to make the message a quoted reply to an earlier
957
+ * message in the same conversation, such as the `data.messageId` of a
958
+ * `message.inbound` webhook. Supported on WhatsApp (every message type except
959
+ * `reaction`) and Telegram. The quoted message must belong to this project
960
+ * (otherwise `404`), must have gone out on the same channel as this send, must
961
+ * belong to the conversation `to` addresses, must have been sent or received by
962
+ * the address this message goes out from (`from`), and must have a
963
+ * `providerMessageId`. A failed message and a Telegram button tap cannot be
964
+ * quoted. Any other case returns `400` instead of sending the message unquoted.
965
+ * The stored message then carries the rest of the `replyTo*` fields.
966
+ *
967
+ * **When receiving:** present on inbound messages that quote an earlier message.
968
+ * Omitted when the quoted message is not found in Zavu (e.g. an old or unknown
969
+ * message) — use replyToProviderMessageId in that case.
970
+ */
971
+ replyToMessageId?: string;
972
+ /**
973
+ * Provider message ID (WhatsApp WAMID, or Telegram message ID) of the quoted
974
+ * message. Present whenever an inbound WhatsApp message is a reply, even if the
975
+ * quoted message is not stored in Zavu, and on outbound quoted replies. Read-only:
976
+ * to quote when sending, set replyToMessageId.
977
+ */
978
+ replyToProviderMessageId?: string;
979
+ /**
980
+ * Sender of the quoted message (phone number in E.164 format, or the Telegram chat
981
+ * ID). Read-only.
982
+ */
983
+ replyToFrom?: string;
984
+ /**
985
+ * Truncated snippet (up to 200 characters) of the quoted message's text, for
986
+ * display. Empty when the quoted message has no text (e.g. media). Read-only.
987
+ */
988
+ replyToText?: string;
989
+ /** Type of the quoted message (text, image, video, etc.). Read-only. */
990
+ replyToMessageType?: string;
991
+ /** Template ID for template messages. */
992
+ templateId?: string;
993
+ /**
994
+ * Variables for body placeholders. Key them to match the template body: by
995
+ * position (`1`, `2`, ...) for positional templates, or by name (e.g.
996
+ * `customer_name`) for named templates. Zavu detects the template's format and
997
+ * sends the correct payload to Meta. Named keys also resolve a named text-header
998
+ * variable. Do not mix positional and named keys in the same request.
999
+ */
1000
+ templateVariables?: {
1001
+ [key: string]: string;
1002
+ };
1003
+ /**
1004
+ * Variables for dynamic button placeholders (URL buttons and OTP buttons). Keys
1005
+ * are the button index (0, 1, 2) in the template's `buttons` array — not the
1006
+ * placeholder name. Values substitute the `{{1}}` placeholder inside that button's
1007
+ * URL.
1008
+ *
1009
+ * **WhatsApp constraints:**
1010
+ * - URL buttons only accept `{{1}}` — positional, numeric, no whitespace, no
1011
+ * name. Named placeholders like `{{token}}` are stored as literal URL text by
1012
+ * Meta and cannot be substituted.
1013
+ * - At most one placeholder per URL button.
1014
+ * - A template may have at most three buttons.
1015
+ * - Static URL buttons (no placeholder) and `quick_reply` buttons are not included
1016
+ * here.
1017
+ */
1018
+ templateButtonVariables?: {
1019
+ [key: string]: string;
1020
+ };
1021
+ /**
1022
+ * Value for a text-header variable, keyed by `1` (WhatsApp text headers allow at
1023
+ * most one variable). Optional override. If omitted, Zavu resolves the header from
1024
+ * `templateVariables` using the header placeholder's name (e.g. `novios`). Static
1025
+ * text headers need no value.
1026
+ */
1027
+ templateHeaderVariables?: {
1028
+ [key: string]: string;
1029
+ };
1030
+ referral?: AdReferral;
1031
+ }
1032
+ export interface MessageContentContactsItem {
1033
+ name?: string;
1034
+ phones?: Array<string>;
1035
+ }
1036
+ export interface MessageContentButtonsItem {
1037
+ id: string;
1038
+ title: string;
1039
+ }
1040
+ export interface MessageContentSectionsItem {
1041
+ title: string;
1042
+ rows: Array<MessageContentSectionsItemRowsItem>;
1043
+ }
1044
+ export interface MessageContentSectionsItemRowsItem {
1045
+ id: string;
1046
+ title: string;
1047
+ description?: string;
1048
+ }
1049
+ export type MessageContentCtaHeaderType = 'text' | 'image' | 'video' | 'document';
1050
+ export type MessageStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'read' | 'failed' | 'received' | 'pending_url_verification';
1051
+ /**
1052
+ * Type of message. Every type except `text` and `template` is sent on WhatsApp
1053
+ * only: the send routes them there whatever `channel` says, and in v2 an explicit
1054
+ * `channel` other than `whatsapp` is refused with `400` naming `messageType` and
1055
+ * `channel`.
1056
+ *
1057
+ * `location_request` asks the recipient to share their location and is
1058
+ * WhatsApp-only. It takes no `content` object — the prompt goes in `text` (max
1059
+ * 1024 characters) and the button label is fixed by WhatsApp. The recipient's
1060
+ * answer arrives as an inbound `location` message whose `content.replyToMessageId`
1061
+ * is the ID of the request.
1062
+ *
1063
+ * `request_contact_info` asks the recipient to share their phone number and is
1064
+ * WhatsApp-only. Like `location_request` it takes no `content` object — the
1065
+ * prompt goes in `text` (max 1024 characters) and WhatsApp renders a fixed **Share
1066
+ * Contact Info** button. The answer arrives as an inbound `contact` message. Use
1067
+ * it to recover the phone number of a contact who adopted a WhatsApp username and
1068
+ * is only known by their business-scoped user ID (BSUID); when they share it, Zavu
1069
+ * automatically links the phone number to that contact.
1070
+ */
1071
+ export type MessageType = 'text' | 'image' | 'video' | 'audio' | 'document' | 'sticker' | 'location' | 'contact' | 'buttons' | 'list' | 'cta_url' | 'request_contact_info' | 'location_request' | 'reaction' | 'template';
1072
+ export interface OwnedPhoneNumber {
1073
+ id: string;
1074
+ phoneNumber: string;
1075
+ /** Optional custom name for the phone number. */
1076
+ name?: string;
1077
+ capabilities: Array<string>;
1078
+ status: PhoneNumberStatus;
1079
+ pricing: OwnedPhoneNumberPricing;
1080
+ /**
1081
+ * Regulatory review state. Numbers that need no review are `approved` immediately.
1082
+ * A number bought with regulatory information is owned and billed from purchase
1083
+ * and starts `pending_review`; it cannot send messages or place calls until this
1084
+ * is `approved`, and its `channels` entry can be absent until then. The state is
1085
+ * re-checked every 6 hours.
1086
+ */
1087
+ regulatoryStatus: OwnedPhoneNumberRegulatoryStatus;
1088
+ nextRenewalDate?: string;
1089
+ createdAt: string;
1090
+ updatedAt?: string;
1091
+ }
1092
+ export type OwnedPhoneNumberRegulatoryStatus = 'approved' | 'pending_review' | 'rejected';
1093
+ export interface OwnedPhoneNumberPricing {
1094
+ /** Monthly price in USD. */
1095
+ monthlyPrice?: number;
1096
+ /** One-time purchase cost in cents. */
1097
+ upfrontCost?: number;
1098
+ /** Monthly cost in cents. */
1099
+ monthlyCost?: number;
1100
+ /** Whether this is a free number. */
1101
+ isFreeNumber?: boolean;
1102
+ }
1103
+ export interface PhoneNumberCapabilities {
1104
+ sms?: boolean;
1105
+ voice?: boolean;
1106
+ mms?: boolean;
1107
+ }
1108
+ export interface PhoneNumberPricing {
1109
+ /** Monthly price in USD. */
1110
+ monthlyPrice?: number;
1111
+ /** One-time purchase price in USD. */
1112
+ upfrontPrice?: number;
1113
+ /**
1114
+ * Whether this number qualifies as the plan-included number: a US or Canadian
1115
+ * number (a +1 number) costing $20 a month or less. The benefit is one per
1116
+ * account: it is never offered again once claimed, not even after the number is
1117
+ * released.
1118
+ */
1119
+ isFreeEligible?: boolean;
1120
+ }
1121
+ export interface PhoneNumberPurchaseRequest {
1122
+ /** Phone number in E.164 format. */
1123
+ phoneNumber: string;
1124
+ /** Optional custom name for the phone number. */
1125
+ name?: string;
1126
+ /**
1127
+ * Type the number was found under in `GET /v2/numbers/available`. Used to look the
1128
+ * number up and to keep regulatory information for reuse. Required when
1129
+ * `regulatoryRequirements` is sent. `toll_free` is accepted as an alias of
1130
+ * `tollFree`. A number not listed under this type is refused with `400
1131
+ * number_unavailable` saying so.
1132
+ */
1133
+ type?: PhoneNumberType;
1134
+ /**
1135
+ * Regulatory information, for numbers whose requirements list is not empty. Get
1136
+ * the list with `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one
1137
+ * entry per requirement id, except `action` requirements, which take no value.
1138
+ * Every required id must be present, once, and no unknown id may be sent;
1139
+ * otherwise the purchase is refused with `400 invalid_request` before anything is
1140
+ * charged.
1141
+ *
1142
+ * The information is kept for your project under the number's country and `type`.
1143
+ * A later purchase there may omit this field if what is kept still covers that
1144
+ * number's requirements. Omit it for numbers without requirements.
1145
+ */
1146
+ regulatoryRequirements?: Array<PhoneNumberPurchaseRequestRegulatoryRequirementsItem>;
1147
+ }
1148
+ export interface PhoneNumberPurchaseRequestRegulatoryRequirementsItem {
1149
+ /**
1150
+ * A `requirementTypes[].id` from `GET /v1/phone-numbers/requirements`. Each id may
1151
+ * appear only once.
1152
+ */
1153
+ requirementType: string;
1154
+ /**
1155
+ * Depends on the requirement's `type`: the text itself for `textual`; for
1156
+ * `address`, the `id` of an address created in this project with `POST
1157
+ * /v1/addresses`; for `document`, the `id` of a document created with `POST
1158
+ * /v1/documents`. An address or document from another project, or one rejected in
1159
+ * review, is refused.
1160
+ */
1161
+ fieldValue: string;
1162
+ }
1163
+ /**
1164
+ * Billing state of an owned number, separate from `regulatoryStatus`. `pending` is
1165
+ * legacy and is not written to numbers today.
1166
+ */
1167
+ export type PhoneNumberStatus = 'active' | 'suspended' | 'pending' | 'releasing' | 'released';
1168
+ /**
1169
+ * Type of phone number. `mobile` is stocked in countries where no geographic
1170
+ * (`local`) or non-geographic (`national`) inventory exists, and in several
1171
+ * markets it is the only type that can receive SMS.
1172
+ */
1173
+ export type PhoneNumberType = 'local' | 'national' | 'tollFree' | 'mobile';
1174
+ /**
1175
+ * The one webhook for everything in the project. Stored apart from the /v1 project
1176
+ * webhook (`/v1/invitations/webhook`); neither API reads or writes the other's.
1177
+ */
1178
+ export interface ProjectWebhookV2 {
1179
+ url: string;
1180
+ /**
1181
+ * Any event in `WebhookEvent`, including `message.*`, `conversation.new` and
1182
+ * `call.*`.
1183
+ */
1184
+ events: Array<WebhookEvent>;
1185
+ active: boolean;
1186
+ signatureVersion: WebhookSignatureVersion;
1187
+ /**
1188
+ * Returned only by `PUT /v2/webhook` when it creates the webhook, and by `POST
1189
+ * /v2/webhook/secret`.
1190
+ */
1191
+ secret?: string;
1192
+ }
1193
+ export interface ProjectWebhookV2Put {
1194
+ /** HTTPS only. */
1195
+ url: string;
1196
+ /**
1197
+ * Any event in `WebhookEvent`. An unknown value is refused with `400` and
1198
+ * `details.allowed`.
1199
+ */
1200
+ events: Array<WebhookEvent>;
1201
+ /** @defaultValue `true` */
1202
+ active?: boolean;
1203
+ signatureVersion?: WebhookSignatureVersion;
1204
+ /**
1205
+ * Switch off the /v1 sender webhooks of this project in the same call, so each
1206
+ * event arrives once. They are only switched off (`webhookActive: false` on /v1);
1207
+ * URL, events and secret stay, so /v1 can turn one back on. Off by default: the
1208
+ * /v2 webhook is added next to them and both receive every event until you decide.
1209
+ * `senderWebhooks` on the response lists what is still on.
1210
+ *
1211
+ * @defaultValue `false`
1212
+ */
1213
+ disableSenderWebhooks?: boolean;
1214
+ }
1215
+ /**
1216
+ * What the engine decided at send time. Reports only decisions the engine makes;
1217
+ * it does not rank channels by price or by WhatsApp window state.
1218
+ */
1219
+ export interface Routing {
1220
+ channel: ChannelType;
1221
+ /**
1222
+ * The address the message leaves from, as `GET /v2/channels` lists it for
1223
+ * `channel`. With a test-mode key, the WhatsApp sandbox number.
1224
+ */
1225
+ from: string;
1226
+ /**
1227
+ * Why this transport was chosen. Closed list:
1228
+ * - `explicit`: `channel` was given.
1229
+ * - `auto_order`: `channel` omitted or `auto`; the first ACTIVE transport of the
1230
+ * sender in a fixed order (for a phone number: WhatsApp, then SMS, then one-way
1231
+ * SMS). A connected transport that is switched off is skipped, not chosen and
1232
+ * then refused. It does not compare price and does not check the WhatsApp
1233
+ * 24-hour window; a closed window fails later as `message.failed`.
1234
+ * - `conversation`: the sender came from `conversationId` (the sender, not the
1235
+ * transport; the transport is then chosen as for `auto_order` unless `channel`
1236
+ * is given).
1237
+ * - `recipient_type`: `to` is an email address, so email.
1238
+ * - `message_type`: `messageType` is WhatsApp-only (media, interactive,
1239
+ * template...), so WhatsApp.
1240
+ * - `sandbox`: test-mode key, which always uses the WhatsApp sandbox.
1241
+ * An automatic fallback is never a send-time reason: it happens later, see
1242
+ * `Message.attemptedChannels`.
1243
+ */
1244
+ reason: RoutingReason;
1245
+ /**
1246
+ * USD this call took from the balance when it was accepted (rounded to 6
1247
+ * decimals). An estimate: for SMS the delivery report can raise it to the real
1248
+ * cost, and `message.charged` shows where it ended up. Present for `sms` and
1249
+ * `sms_oneway`. Null otherwise — WhatsApp is billed by Meta, email in
1250
+ * 1,000-message blocks, voice per minute — and also null while a message waits
1251
+ * for URL verification, which is charged when it is released. Null means "not
1252
+ * known at send time", not "free".
1253
+ */
1254
+ estimatedCost: number | null;
1255
+ }
1256
+ export type RoutingReason = 'explicit' | 'auto_order' | 'conversation' | 'recipient_type' | 'message_type' | 'sandbox';
1257
+ /**
1258
+ * Request body to send a message. No `Zavu-Sender` header: where it leaves from
1259
+ * comes from `conversationId`, then `from`, then the project default. `to` is
1260
+ * required, except with `conversationId`, where it defaults to whoever the
1261
+ * conversation is with.
1262
+ */
1263
+ export interface SendMessageRequest {
1264
+ /**
1265
+ * Recipient phone number in E.164 format, email address, WhatsApp business-scoped
1266
+ * user ID (BSUID, e.g. `US.13491208655302741918`), or numeric chat ID (for
1267
+ * Telegram/Instagram/Messenger). A phone number written with spaces, dashes, dots
1268
+ * or parentheses after its `+` (`+56 9 1234 5678`) is read as the E.164 number;
1269
+ * bare digits are not (see `400` on this operation). A BSUID is routed to WhatsApp
1270
+ * and sent via the `recipient` field; use it to message a contact who adopted a
1271
+ * username and whose phone number is hidden.
1272
+ *
1273
+ * Required unless `conversationId` is given. With `conversationId` it may be
1274
+ * omitted (it is the conversation's contact: its email for `channel: "email"`,
1275
+ * else the identifier it is filed under); if given it must be one of that
1276
+ * conversation's identifiers (its key, email or BSUID, in any formatting), else
1277
+ * `400` naming `to` and `conversationId`.
1278
+ */
1279
+ to?: string;
1280
+ channel?: ChannelTypeRequest;
1281
+ /**
1282
+ * Type of message. Defaults to 'text'.
1283
+ *
1284
+ * @defaultValue `"text"`
1285
+ */
1286
+ messageType?: MessageType;
1287
+ /** Text body for text messages or caption for media messages. */
1288
+ text?: string;
1289
+ /** Additional content for non-text message types. */
1290
+ content?: MessageContent;
1291
+ /**
1292
+ * Email subject line. Required when channel is 'email' or recipient is an email
1293
+ * address.
1294
+ */
1295
+ subject?: string;
1296
+ /**
1297
+ * HTML body for email messages. If provided, email will be sent as multipart with
1298
+ * both text and HTML.
1299
+ */
1300
+ htmlBody?: string;
1301
+ /** Reply-To email address for email messages. */
1302
+ replyTo?: string;
1303
+ /** Optional idempotency key to avoid duplicate sends. */
1304
+ idempotencyKey?: string;
1305
+ /** Arbitrary metadata to associate with the message. */
1306
+ metadata?: {
1307
+ [key: string]: string;
1308
+ };
1309
+ /**
1310
+ * Whether to enable automatic fallback to SMS if WhatsApp fails. Defaults to true.
1311
+ *
1312
+ * @defaultValue `true`
1313
+ */
1314
+ fallbackEnabled?: boolean;
1315
+ /**
1316
+ * Language code for voice text-to-speech (e.g., 'en-US', 'es-ES', 'pt-BR'). If
1317
+ * omitted, language is auto-detected from recipient's country code.
1318
+ */
1319
+ voiceLanguage?: string;
1320
+ /**
1321
+ * Email attachments. Only supported when channel is 'email'. Maximum 40MB total
1322
+ * size.
1323
+ */
1324
+ attachments?: Array<EmailAttachmentInput>;
1325
+ /**
1326
+ * Which of your addresses sends (see `GET /v2/channels`): an E.164 number in any
1327
+ * common formatting, an email address, `@botname`, `@username`, a Page id.
1328
+ * Resolved inside your project only. Omitted: the project default, the same one
1329
+ * /v1 uses when no `Zavu-Sender` header is sent. Ignored when `conversationId` is
1330
+ * set, and with a test-mode key, which always sends from the WhatsApp sandbox.
1331
+ *
1332
+ * An address that no entry has returns `404 not_found`. An address two of your
1333
+ * senders share (a number whose WhatsApp was connected on one sender and SMS on
1334
+ * another) resolves when `channel` names the transport; otherwise it returns `409
1335
+ * ambiguous_from` with `details.candidates[{address, type, v1SenderId}]`, and in
1336
+ * that case, and only then, `from` also accepts one of those `v1SenderId` values.
1337
+ */
1338
+ from?: string;
1339
+ /**
1340
+ * Reply inside an existing conversation: the message leaves from the sender that
1341
+ * last handled it (`from` on the Conversation), and goes to whoever the
1342
+ * conversation is with, so `to` may be omitted. A `to` that is not the
1343
+ * conversation's contact is refused with `400` (`details.errors` on `to` and
1344
+ * `conversationId`, `details.conversationTo`) instead of silently opening another
1345
+ * conversation. Takes precedence over `from`. When `channel` is omitted,
1346
+ * `routing.reason` is then `conversation`. A conversation of another project
1347
+ * returns `404`; one with no sender recorded returns `409 no_channel`. The 202's
1348
+ * `message.conversationId` is set whenever the conversation the message is filed
1349
+ * in already exists; it is absent only for a recipient's first message, whose
1350
+ * conversation is created after the response. A reply to a conversation that an
1351
+ * inbound email opened reaches the right person but is filed in a separate
1352
+ * conversation keyed by the email address.
1353
+ */
1354
+ conversationId?: string;
1355
+ }
1356
+ export interface SendMessageResponse {
1357
+ message: Message;
1358
+ routing: Routing;
1359
+ }
1360
+ export interface Template {
1361
+ id: string;
1362
+ /** Template name. For WhatsApp, must match the approved template name in Meta. */
1363
+ name: string;
1364
+ /** Language code. */
1365
+ language: string;
1366
+ /**
1367
+ * Default template body with variables: positional ({{1}}, {{2}}) or named
1368
+ * ({{customer_name}}, {{contact.first_name}}). Templates created in Zavu are
1369
+ * submitted to Meta as positional; templates imported from a WhatsApp Business
1370
+ * Account keep their original format (named or positional). Used when no
1371
+ * channel-specific body is set.
1372
+ */
1373
+ body: string;
1374
+ /** Channel-specific body for SMS messages. Falls back to `body` if not set. */
1375
+ smsBody?: string;
1376
+ /** Channel-specific body for Telegram messages. Falls back to `body` if not set. */
1377
+ telegramBody?: string;
1378
+ /** Channel-specific body for Instagram messages. Falls back to `body` if not set. */
1379
+ instagramBody?: string;
1380
+ /**
1381
+ * The category the template is billed under. For a template linked to WhatsApp
1382
+ * this is the category **Meta currently assigns**, not the one it was submitted
1383
+ * with: Meta can recategorize a template at approval or at any point afterwards,
1384
+ * and that changes what the message costs.
1385
+ *
1386
+ * A recategorization reaches this field through the `template.status_changed`
1387
+ * webhook, which carries `data.category`, and through `POST /v1/templates/sync`,
1388
+ * which reconciles it against Meta. Read one of those rather than assuming the
1389
+ * category you sent is the one in force.
1390
+ *
1391
+ * For a template that was never submitted to WhatsApp, this is the category stored
1392
+ * locally, defaulting to `UTILITY`.
1393
+ */
1394
+ category: WhatsAppCategory;
1395
+ /** @defaultValue `"draft"` */
1396
+ status?: TemplateStatus;
1397
+ /** List of variable names for documentation. */
1398
+ variables?: Array<string>;
1399
+ /** Type of header (text, image, video, document). */
1400
+ headerType?: string;
1401
+ /** Header content (text or media URL). */
1402
+ headerContent?: string;
1403
+ /** Footer text for the template. */
1404
+ footer?: string;
1405
+ /** Template buttons. */
1406
+ buttons?: Array<TemplateButtonsItem>;
1407
+ /** Add 'Do not share this code' disclaimer. Only for AUTHENTICATION templates. */
1408
+ addSecurityRecommendation?: boolean;
1409
+ /** Code expiration time in minutes. Only for AUTHENTICATION templates. */
1410
+ codeExpirationMinutes?: number;
1411
+ /** WhatsApp-specific template information. */
1412
+ whatsapp?: TemplateWhatsapp;
1413
+ createdAt?: string;
1414
+ updatedAt?: string;
1415
+ }
1416
+ export type TemplateStatus = 'draft' | 'pending' | 'approved' | 'rejected';
1417
+ export interface TemplateButtonsItem {
1418
+ type?: TemplateButtonsItemType;
1419
+ text?: string;
1420
+ url?: string;
1421
+ /**
1422
+ * Sample value used to substitute `{{1}}` in the URL when submitting the template
1423
+ * to Meta for review. Only present for dynamic URL buttons.
1424
+ */
1425
+ example?: string;
1426
+ phoneNumber?: string;
1427
+ /** OTP button type. Required when type is 'otp'. */
1428
+ otpType?: TemplateButtonsItemOtpType;
1429
+ /** Android package name. Required for ONE_TAP buttons. */
1430
+ packageName?: string;
1431
+ /** Android app signature hash. Required for ONE_TAP buttons. */
1432
+ signatureHash?: string;
1433
+ }
1434
+ export type TemplateButtonsItemType = 'quick_reply' | 'url' | 'phone' | 'otp' | 'request_contact_info';
1435
+ export type TemplateButtonsItemOtpType = 'COPY_CODE' | 'ONE_TAP';
1436
+ export interface TemplateWhatsapp {
1437
+ /** WhatsApp template name. */
1438
+ templateName?: string;
1439
+ /** WhatsApp Business Account namespace. */
1440
+ namespace?: string;
1441
+ /** WhatsApp approval status. */
1442
+ status?: string;
1443
+ }
1444
+ export interface TemplateCreateRequest {
1445
+ name: string;
1446
+ /** @defaultValue `"en"` */
1447
+ language: string;
1448
+ /** Default template body. Used when no channel-specific body is set. */
1449
+ body: string;
1450
+ /** Channel-specific body for SMS. Falls back to `body` if not set. */
1451
+ smsBody?: string;
1452
+ /** Channel-specific body for Telegram. Falls back to `body` if not set. */
1453
+ telegramBody?: string;
1454
+ /** Channel-specific body for Instagram. Falls back to `body` if not set. */
1455
+ instagramBody?: string;
1456
+ whatsappCategory?: WhatsAppCategory;
1457
+ /** Type of header for the template. */
1458
+ headerType?: TemplateCreateRequestHeaderType;
1459
+ /** Header content (text string or media URL). */
1460
+ headerContent?: string;
1461
+ /** Footer text for the template. */
1462
+ footer?: string;
1463
+ variables?: Array<string>;
1464
+ /** Template buttons (max 3). */
1465
+ buttons?: Array<TemplateCreateRequestButtonsItem>;
1466
+ /** Add 'Do not share this code' disclaimer. Only for AUTHENTICATION templates. */
1467
+ addSecurityRecommendation?: boolean;
1468
+ /** Code expiration time in minutes. Only for AUTHENTICATION templates. */
1469
+ codeExpirationMinutes?: number;
1470
+ }
1471
+ export type TemplateCreateRequestHeaderType = 'text' | 'image' | 'video' | 'document';
1472
+ export interface TemplateCreateRequestButtonsItem {
1473
+ /**
1474
+ * `request_contact_info` renders a fixed **Share Contact Info** button that asks
1475
+ * the recipient to share their phone number — useful when a contact adopted a
1476
+ * WhatsApp username and you only know their BSUID. It takes no other fields.
1477
+ */
1478
+ type: TemplateCreateRequestButtonsItemType;
1479
+ /**
1480
+ * Button label. Required for every type except `request_contact_info`, whose label
1481
+ * is fixed by WhatsApp.
1482
+ */
1483
+ text?: string;
1484
+ /**
1485
+ * Button destination. Use `{{1}}` exactly once for a dynamic URL (e.g.
1486
+ * `https://example.com/orders/{{1}}`); WhatsApp only accepts the strict `{{1}}`
1487
+ * form. Static URLs must not contain any `{{...}}` placeholder.
1488
+ */
1489
+ url?: string;
1490
+ /**
1491
+ * Sample value Meta uses to review templates with a dynamic URL button.
1492
+ * Substituted into `{{1}}` of the URL when the template is submitted to Meta. Only
1493
+ * meaningful when `url` contains `{{1}}`; ignored for static URLs.
1494
+ */
1495
+ example?: string;
1496
+ phoneNumber?: string;
1497
+ /**
1498
+ * Required when type is 'otp'. COPY_CODE shows copy button, ONE_TAP enables
1499
+ * Android autofill.
1500
+ */
1501
+ otpType?: TemplateCreateRequestButtonsItemOtpType;
1502
+ /** Android package name. Required for ONE_TAP buttons. */
1503
+ packageName?: string;
1504
+ /** Android app signature hash. Required for ONE_TAP buttons. */
1505
+ signatureHash?: string;
1506
+ }
1507
+ export type TemplateCreateRequestButtonsItemType = 'quick_reply' | 'url' | 'phone' | 'otp' | 'request_contact_info';
1508
+ export type TemplateCreateRequestButtonsItemOtpType = 'COPY_CODE' | 'ONE_TAP';
1509
+ export interface TemplateSubmitRequest {
1510
+ /**
1511
+ * The WhatsApp number whose Business Account receives the template: an address
1512
+ * with a `whatsapp` entry in `GET /v2/channels`.
1513
+ */
1514
+ from: string;
1515
+ category?: WhatsAppCategory;
1516
+ }
1517
+ /**
1518
+ * Type of event that triggers the webhook.
1519
+ *
1520
+ * **Message lifecycle events:**
1521
+ * - `message.queued`: Message created and queued for sending. `data.status` =
1522
+ * `queued`
1523
+ * - `message.sent`: Message accepted by the provider. `data.status` = `sent`
1524
+ * - `message.delivered`: Message delivered to recipient. `data.status` =
1525
+ * `delivered`
1526
+ * - `message.read`: Message was read by the recipient (WhatsApp only).
1527
+ * `data.status` = `read`
1528
+ * - `message.failed`: Message failed to send. `data.status` = `failed`
1529
+ *
1530
+ * **Inbound events:**
1531
+ * - `message.inbound`: New message received from a contact. `data.conversationId`,
1532
+ * the inbox thread id (deep-link with
1533
+ * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`), is sent on
1534
+ * **email** messages only, and is `null` there on the first message of a
1535
+ * brand-new thread. On every other channel it is absent: read it from `GET
1536
+ * /v2/messages/{messageId}`, which always has it, or from `conversation.new` for
1537
+ * a new contact. Reactions are delivered as `message.inbound` with
1538
+ * `messageType='reaction'`. When the contact replied to (quoted) an earlier
1539
+ * message, `data.content` carries the reply context: `replyToMessageId`,
1540
+ * `replyToProviderMessageId`, `replyToFrom`, `replyToText`, and
1541
+ * `replyToMessageType`. `data.providerTimestamp` is the provider's original
1542
+ * receive time in Unix milliseconds (the moment the channel received the message
1543
+ * from the contact — WhatsApp, Telegram, Instagram, Messenger; `null` for SMS
1544
+ * and email). Compare it against the top-level `timestamp` (when Zavu dispatched
1545
+ * the webhook) to detect and ignore delayed deliveries. When the conversation
1546
+ * was opened from a Click-to-WhatsApp ad or post, `data.referral` carries the ad
1547
+ * attribution — including `ctwaClid`, the identifier Meta's Conversions API
1548
+ * needs to credit a conversion back to that ad. WhatsApp only, and only on the
1549
+ * first message of the thread: it is absent from every later message, so persist
1550
+ * it when it arrives.
1551
+ * - `message.unsupported`: Received a message type that is not supported
1552
+ *
1553
+ * **Broadcast events:**
1554
+ * - `broadcast.status_changed`: Broadcast status changed (pending_review,
1555
+ * approved, rejected, sending, completed, cancelled)
1556
+ *
1557
+ * **Other events:**
1558
+ * - `conversation.new`: New conversation started with a contact. `data` carries
1559
+ * `conversationId` (the inbox thread id — deep-link with
1560
+ * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`), the
1561
+ * `phoneNumber` or `email` key, `channel`, `firstMessageId`, `firstMessageText`,
1562
+ * and `profileName`.
1563
+ * - `template.status_changed`: WhatsApp template approval status changed. `data`
1564
+ * carries `templateId`, `name`, `previousStatus`, `currentStatus`,
1565
+ * `rejectionReason`, and `category` — the category Meta currently bills the
1566
+ * template under. Meta can recategorize a template (typically `UTILITY` to
1567
+ * `MARKETING`) at approval or long afterwards, which changes what each message
1568
+ * costs; `category` is how that reaches you. A recategorization with no status
1569
+ * change is delivered as this same event, so compare `category` against what you
1570
+ * hold rather than only reacting to `currentStatus`.
1571
+ *
1572
+ * **Partner events:**
1573
+ * - `invitation.status_changed`: A partner invitation's stored status changed: to
1574
+ * `in_progress`, `completed`, `failed`, `cancelled`, or back to `pending` when
1575
+ * it is resent from the dashboard. A change to the same status sends nothing,
1576
+ * and expiry is not a stored change, so no event is sent when an invitation
1577
+ * expires. Delivered to the project that created the invitation; a parent
1578
+ * project does not receive its sub-accounts' events. `data` carries
1579
+ * `invitationId`, `clientName`, `clientEmail`, `connectionType` (`whatsapp_waba`
1580
+ * or `messenger`), `previousStatus`, and `currentStatus`. On `completed` it also
1581
+ * carries `connectedAccount` (`channel`, `id`, `name`), the WhatsApp number or
1582
+ * Facebook Page that was linked, and, for WhatsApp, `wabaAccountId`. On `failed`
1583
+ * it carries `failureReason`; the invitation link stays usable, so a client can
1584
+ * retry it.
1585
+ *
1586
+ * **Voice Agent events:**
1587
+ * For every voice event, `data` carries `callId`, `direction`, `from`, `to`,
1588
+ * `status`, `durationSeconds`, `endReason`, and `transcriptAvailable`. The
1589
+ * terminal events (`call.completed`, `call.failed`) additionally carry `cost` —
1590
+ * what the call was billed, in USD, combining telephony and the managed voice
1591
+ * pipeline — and `currency`. They are dispatched after the call is charged, so
1592
+ * `cost` is populated rather than zero; telephony can still be settling on an
1593
+ * outbound call, in which case `GET /v1/calls/{callId}` holds the reconciled
1594
+ * figure.
1595
+ * - `call.initiated`: An outbound call was created and is dialing, or an inbound
1596
+ * call was received. `data.status` = `ringing`
1597
+ * - `call.answered`: The call was answered and the voice agent is connected.
1598
+ * `data.status` = `in_progress`
1599
+ * - `call.completed`: The call ended after a conversation. `data.status` =
1600
+ * `completed`; `durationSeconds` and `endReason` describe how it ended, and
1601
+ * `transcriptAvailable` indicates whether a transcript can be fetched.
1602
+ * - `call.failed`: The call could not be completed (busy, no answer, canceled, or
1603
+ * an error). `data.status` is the terminal status and `endReason` explains the
1604
+ * cause.
1605
+ *
1606
+ * **Custom domain events:**
1607
+ * - `domain.verified`: A custom email domain passed verification (DKIM, and
1608
+ * SPF/DMARC/MAIL FROM if enhanced records are enabled)
1609
+ * - `domain.failed`: A custom email domain failed verification or is partially
1610
+ * verified
1611
+ */
1612
+ export type WebhookEvent = 'message.queued' | 'message.sent' | 'message.delivered' | 'message.read' | 'message.failed' | 'message.inbound' | 'message.unsupported' | 'broadcast.status_changed' | 'conversation.new' | 'template.status_changed' | 'invitation.status_changed' | 'call.initiated' | 'call.answered' | 'call.completed' | 'call.failed' | 'domain.verified' | 'domain.failed';
1613
+ /**
1614
+ * Data payload for message webhook events (queued, sent, delivered, failed,
1615
+ * inbound).
1616
+ */
1617
+ export interface WebhookMessageData {
1618
+ /** ID of the message. */
1619
+ messageId: string;
1620
+ /**
1621
+ * Recipient phone number or email. On `message.inbound` this is your own number
1622
+ * (the message's destination).
1623
+ */
1624
+ to: string;
1625
+ /**
1626
+ * Sender of the message. Present on `message.inbound`: the contact who sent the
1627
+ * message.
1628
+ */
1629
+ from?: string;
1630
+ channel: ChannelType;
1631
+ status: MessageStatus;
1632
+ /** Type of the message. Present on `message.inbound`. */
1633
+ messageType?: MessageType;
1634
+ /**
1635
+ * ID of the conversation (inbox thread) this message belongs to. Sent on
1636
+ * `message.inbound` for **email** messages only; on SMS, WhatsApp, Telegram,
1637
+ * Instagram and Messenger it is absent. Use it to deep-link to the dashboard
1638
+ * inbox: `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`. On
1639
+ * email it is `null` on the first message of a brand-new thread. In every case,
1640
+ * fetch it via `GET /v2/messages/{messageId}`, whose `conversationId` is always
1641
+ * populated, or take it from the `conversation.new` event for a new contact.
1642
+ */
1643
+ conversationId?: string | null;
1644
+ /**
1645
+ * Text body or media caption. Present on `message.inbound` when the message has
1646
+ * text.
1647
+ */
1648
+ text?: string;
1649
+ /** Error code if the message failed. */
1650
+ errorCode?: string | null;
1651
+ /** Error message if the message failed. */
1652
+ errorMessage?: string | null;
1653
+ /**
1654
+ * The provider's original receive time in Unix milliseconds (when the channel
1655
+ * received the message from the contact). Present on `message.inbound` for
1656
+ * channels that report it (WhatsApp, Telegram, Instagram, Messenger); null for SMS
1657
+ * and email.
1658
+ */
1659
+ providerTimestamp?: number | null;
1660
+ /**
1661
+ * Click-to-WhatsApp ad attribution. Present on `message.inbound` only when this is
1662
+ * the first message of a conversation opened from a Meta ad or post — absent on
1663
+ * every later message in that same thread, and on organic conversations. Read
1664
+ * `referral.ctwaClid` here to attribute the conversation, and persist it on your
1665
+ * side: this webhook is the only delivery. `GET /v2/messages/{messageId}` also
1666
+ * returns it, under `content.referral`.
1667
+ */
1668
+ referral?: AdReferral;
1669
+ }
1670
+ /**
1671
+ * What a `POST` to your /v2 webhook carries. Signed like every Zavu webhook
1672
+ * (`X-Zavu-Signature`, with the webhook's `signatureVersion`); the event name is
1673
+ * also in the `X-Zavu-Event` header. No sender id appears anywhere in it.
1674
+ */
1675
+ export interface WebhookPayloadV2 {
1676
+ /**
1677
+ * Unique event identifier. Different from the id of the same event delivered to a
1678
+ * /v1 webhook.
1679
+ */
1680
+ id: string;
1681
+ event: WebhookEvent;
1682
+ /** Unix milliseconds when the event was created. */
1683
+ timestamp: number;
1684
+ projectId: string;
1685
+ /**
1686
+ * Where the event's message or call came from. Outbound message events: your
1687
+ * address. `message.inbound`, `message.unsupported`, `conversation.new`: the
1688
+ * contact. `call.*`: the caller. Project-level events (`invitation.*`, `domain.*`,
1689
+ * `broadcast.*`) are not about one address: read `data`. On those, `from`, `to`
1690
+ * and `type` can be null, or name an address of the channel group the event was
1691
+ * recorded on.
1692
+ */
1693
+ from: string | null;
1694
+ /**
1695
+ * The other end: the recipient of an outbound message, your address for an inbound
1696
+ * one, the callee of a call.
1697
+ */
1698
+ to: string | null;
1699
+ /** The transport, as in `GET /v2/channels`. Null when the event names none. */
1700
+ type: ChannelType | null;
1701
+ /** The same event data /v1 sends (see `WebhookEvent`), without `senderId`. */
1702
+ data: {
1703
+ [key: string]: unknown;
1704
+ };
1705
+ }
1706
+ /**
1707
+ * Which `X-Zavu-Signature` scheme this receiver is sent. The header is `t=<unix
1708
+ * seconds>` followed by the signatures.
1709
+ *
1710
+ * - `v1`: `v1=HMAC_SHA256(secret, body)`.
1711
+ * - `v2`: `v2=HMAC_SHA256(secret, "{t}.{body}")`. The current scheme, and the
1712
+ * default for a new /v2 webhook. It signs the timestamp together with the body.
1713
+ * - `v1+v2`: both signatures, sharing one `t`. The migration setting: a receiver
1714
+ * reading either one works.
1715
+ *
1716
+ * Moving straight between `v1` and `v2`, in either direction, returns `400`. Set
1717
+ * `v1+v2` first. See
1718
+ * https://docs.zavu.dev/guides/receiving-messages/signature-migration
1719
+ */
1720
+ export type WebhookSignatureVersion = 'v1' | 'v1+v2' | 'v2';
1721
+ /** WhatsApp template category. */
1722
+ export type WhatsAppCategory = 'UTILITY' | 'MARKETING' | 'AUTHENTICATION';
1723
+ /** One place the project can send from, on one transport. */
1724
+ export interface ChannelEntry {
1725
+ /**
1726
+ * The address the recipient sees: an E.164 number (`sms`, `voice`, `whatsapp`), an
1727
+ * email address (lowercase), `@botname` (`telegram`), `@username` (`instagram`),
1728
+ * the Facebook Page id (`messenger`), or the literal `sms_oneway` (one-way SMS
1729
+ * goes out from shared system numbers, and messages on it store this same literal
1730
+ * as `from`).
1731
+ */
1732
+ address: string;
1733
+ type: ChannelType;
1734
+ /**
1735
+ * It can send right now. A connected transport that is switched off is listed with
1736
+ * `active: false`; turn it on with `POST /v2/channels/{address}/{type}/activate`.
1737
+ * `sms`, `sms_oneway` and `voice` have no switch and are always active.
1738
+ */
1739
+ active: boolean;
1740
+ /**
1741
+ * Read-only. The /v1 sender behind this entry, usable as the `Zavu-Sender` header
1742
+ * on /v1. Entries with the same `v1SenderId` are one channel group. On /v2 it is
1743
+ * accepted as `from` only when two entries of different groups share an address
1744
+ * (see `409 ambiguous_from`).
1745
+ */
1746
+ v1SenderId: string;
1747
+ }
1748
+ /**
1749
+ * A /v1 sender webhook that is still on. Each one also receives the events it is
1750
+ * subscribed to, as a separate delivery.
1751
+ */
1752
+ export interface SenderWebhookV1 {
1753
+ /** The sender's first address; null for a sender with no connected transport. */
1754
+ address: string | null;
1755
+ url: string;
1756
+ /** Read-only; the sender to change on /v1. */
1757
+ v1SenderId: string;
1758
+ }
1759
+ /**
1760
+ * What to connect. Only channels that need no purchase and no third-party signup
1761
+ * are connected here: one-way SMS, an email address at a verified domain, a
1762
+ * Telegram bot. Two-way SMS and voice come with a number (`POST /v2/numbers`);
1763
+ * WhatsApp, Instagram and Messenger connect through Meta, from Accounts in the
1764
+ * dashboard. Any of those types here is a `400` saying so.
1765
+ */
1766
+ export type ChannelConnectRequest = ChannelConnectRequestSmsOneway | ChannelConnectRequestEmail | ChannelConnectRequestTelegram;
1767
+ export interface EmailDomain {
1768
+ id: string;
1769
+ domain: string;
1770
+ /** Overall verification status. */
1771
+ status: string;
1772
+ dkimStatus: string;
1773
+ /**
1774
+ * DNS records to publish. Present when fetching a single domain or after adding
1775
+ * one.
1776
+ */
1777
+ dnsRecords?: Array<EmailDomainDnsRecord>;
1778
+ /**
1779
+ * Present with `dnsRecords`. False when the DKIM records could not be generated:
1780
+ * such a domain cannot verify whatever DNS you publish, and `setupError` says what
1781
+ * to do.
1782
+ */
1783
+ verifiable?: boolean;
1784
+ /**
1785
+ * Present when `verifiable` is false. `recommendation` is the same everywhere this
1786
+ * domain is refused (`POST .../verify`, `POST /v2/channels`): remove the domain
1787
+ * and add it again, which sets it up from scratch; contact support if the new one
1788
+ * has no `dkim` record either. It never says to retry verify or to publish the
1789
+ * other records.
1790
+ */
1791
+ setupError?: EmailDomainSetupError;
1792
+ }
1793
+ export interface EmailDomainSetupError {
1794
+ code?: 'dkim_records_unavailable';
1795
+ message?: string;
1796
+ recommendation?: string;
1797
+ }
1798
+ export interface EmailDomainDnsRecord {
1799
+ /** DNS record type. */
1800
+ type: string;
1801
+ /** Record host/name to create. */
1802
+ name: string;
1803
+ /** Record value. */
1804
+ value: string;
1805
+ /** Priority (MX records only). */
1806
+ priority?: number;
1807
+ /** What the record is for. */
1808
+ purpose: EmailDomainDnsRecordPurpose;
1809
+ /**
1810
+ * Whether the record is required to verify + send (DKIM) or recommended for
1811
+ * deliverability.
1812
+ */
1813
+ required: boolean;
1814
+ }
1815
+ export type EmailDomainDnsRecordPurpose = 'dkim' | 'spf' | 'dmarc' | 'mail_from';
1816
+ /**
1817
+ * A Zavu Function: TypeScript that runs in Zavu Cloud, either reacting to events,
1818
+ * serving HTTP, or holding the agents its code declares.
1819
+ */
1820
+ export interface ZavuFunction {
1821
+ id: string;
1822
+ slug: string;
1823
+ name: string;
1824
+ description?: string | null;
1825
+ runtime: string;
1826
+ status: FunctionStatus;
1827
+ /**
1828
+ * True only while a version is live and not paused (`status: active`). A draft, a
1829
+ * failed first deploy, a deploy in progress or a pause are all `false`.
1830
+ */
1831
+ enabled: boolean;
1832
+ timeoutSec: number;
1833
+ memoryMb: FunctionMemoryMb;
1834
+ /**
1835
+ * arm64 is the default and the cheaper one; x86_64 bills each invocation at 1.25x
1836
+ * units. Applied on the next deploy.
1837
+ */
1838
+ architecture: FunctionArchitecture;
1839
+ httpEnabled: boolean;
1840
+ /** Null while `httpEnabled` is false: the URL does not serve then. */
1841
+ publicUrl?: string | null;
1842
+ activeDeploymentId?: string | null;
1843
+ createdAt: string;
1844
+ updatedAt: string;
1845
+ /**
1846
+ * The customer paused it. A deploy, a git push or a rollback does not resume it.
1847
+ * Pausing stops event triggers; the HTTP endpoint has its own switch,
1848
+ * `httpEnabled`, and the tools of the agents it declares keep answering.
1849
+ */
1850
+ paused: boolean;
1851
+ }
1852
+ export type FunctionStatus = 'draft' | 'deploying' | 'active' | 'failed' | 'disabled';
1853
+ export type FunctionMemoryMb = 128 | 256 | 512 | 1024;
1854
+ export type FunctionArchitecture = 'arm64' | 'x86_64';
1855
+ /**
1856
+ * Configuration only, applied in one transaction: if any part is refused, nothing
1857
+ * changes. Code, dependencies and deploys are on /v1 (`PATCH
1858
+ * /v1/functions/{functionId}` and `POST /v1/functions/{functionId}/deploy`). Send
1859
+ * at least one field. Every invalid field is reported in `details.errors`.
1860
+ */
1861
+ export interface FunctionUpdateRequest {
1862
+ name?: string;
1863
+ /** null clears it. */
1864
+ description?: string | null;
1865
+ /** Applied on the next deploy. */
1866
+ timeoutSec?: number;
1867
+ /** Applied on the next deploy. */
1868
+ memoryMb?: FunctionUpdateRequestMemoryMb;
1869
+ architecture?: FunctionUpdateRequestArchitecture;
1870
+ /**
1871
+ * false pauses the function, true resumes it. Refused with 409
1872
+ * `function_not_ready` while it is a draft, deploying, or its first deploy failed.
1873
+ */
1874
+ enabled?: boolean;
1875
+ /**
1876
+ * Switch the public endpoint on or off. Applies to the deployed function without a
1877
+ * redeploy.
1878
+ */
1879
+ httpEnabled?: boolean;
1880
+ }
1881
+ export type FunctionUpdateRequestMemoryMb = 128 | 256 | 512 | 1024;
1882
+ export type FunctionUpdateRequestArchitecture = 'arm64' | 'x86_64';
1883
+ /**
1884
+ * One-way SMS from shared system numbers. No number or credential; recipients
1885
+ * cannot reply. Sends within the SMS daily ceiling. Sending to a US or Canadian
1886
+ * (+1) number needs an approved 10DLC campaign first, and is refused with `403
1887
+ * ten_dlc_required` until then. Refused with `403 kyb_required` only on an account
1888
+ * that must verify its business before using one-way SMS.
1889
+ */
1890
+ export interface ChannelConnectRequestSmsOneway {
1891
+ type: 'sms_oneway';
1892
+ }
1893
+ /**
1894
+ * An address at an email domain of this project that is verified (`GET
1895
+ * /v2/email-domains`).
1896
+ */
1897
+ export interface ChannelConnectRequestEmail {
1898
+ type: 'email';
1899
+ address: string;
1900
+ /** Display name in the recipient's inbox. */
1901
+ fromName?: string;
1902
+ }
1903
+ /** A Telegram bot. Its address is `@botname`. */
1904
+ export interface ChannelConnectRequestTelegram {
1905
+ type: 'telegram';
1906
+ /** Bot token from @BotFather. */
1907
+ botToken: string;
1908
+ }
1909
+ export type ListMessagesV2Status = 'queued' | 'sending' | 'sent' | 'delivered' | 'failed' | 'received';
1910
+ export interface ListMessagesV2Response {
1911
+ items: Array<Message>;
1912
+ nextCursor?: string | null;
1913
+ }
1914
+ export interface GetMessageV2Response {
1915
+ message: Message;
1916
+ }
1917
+ export interface ListConversationsV2Response {
1918
+ items: Array<Conversation>;
1919
+ nextCursor?: string | null;
1920
+ }
1921
+ export interface GetConversationV2Response {
1922
+ conversation: Conversation;
1923
+ }
1924
+ export interface ListConversationMessagesV2Response {
1925
+ items: Array<Message>;
1926
+ nextCursor?: string | null;
1927
+ }
1928
+ export interface MarkConversationReadV2Response {
1929
+ conversation: Conversation;
1930
+ }
1931
+ export interface ListContactsV2Response {
1932
+ items: Array<Contact>;
1933
+ nextCursor?: string | null;
1934
+ }
1935
+ export interface ListChannelsV2Response {
1936
+ items: Array<ChannelEntry>;
1937
+ nextCursor?: string | null;
1938
+ }
1939
+ export interface ConnectChannelV2Response {
1940
+ items: Array<ChannelEntry>;
1941
+ }
1942
+ export interface ListTemplatesV2Response {
1943
+ items: Array<Template>;
1944
+ nextCursor?: string | null;
1945
+ }
1946
+ export interface ListCampaignsV2Response {
1947
+ items: Array<Broadcast>;
1948
+ nextCursor: string | null;
1949
+ }
1950
+ export interface CreateCampaignV2Response {
1951
+ campaign: Broadcast;
1952
+ }
1953
+ export interface GetCampaignV2Response {
1954
+ campaign: Broadcast;
1955
+ }
1956
+ export interface SendCampaignV2Response {
1957
+ campaign: Broadcast;
1958
+ }
1959
+ export interface GetWebhookV2Response {
1960
+ webhook: ProjectWebhookV2 | null;
1961
+ senderWebhooks: Array<SenderWebhookV1>;
1962
+ }
1963
+ export interface PutWebhookV2Response {
1964
+ webhook: ProjectWebhookV2;
1965
+ senderWebhooks: Array<SenderWebhookV1>;
1966
+ /** How many /v1 sender webhooks this call switched off. */
1967
+ disabledSenderWebhooks: number;
1968
+ }
1969
+ export interface RotateWebhookSecretV2Response {
1970
+ secret: string;
1971
+ }
1972
+ export interface ListAgentsV2Response {
1973
+ items: Array<Agent>;
1974
+ nextCursor?: string | null;
1975
+ }
1976
+ export interface CreateAgentV2Response {
1977
+ agent: Agent;
1978
+ }
1979
+ export interface GetAgentV2Response {
1980
+ agent: Agent;
1981
+ }
1982
+ export interface UpdateAgentV2Response {
1983
+ agent: Agent;
1984
+ }
1985
+ export interface GetChannelV2Response {
1986
+ items: Array<ChannelEntry>;
1987
+ }
1988
+ export interface ActivateChannelV2Response {
1989
+ address: string;
1990
+ type: ActivatableChannel;
1991
+ /** Every entry of the address after the change. */
1992
+ channels: Array<ChannelEntry>;
1993
+ activated: boolean;
1994
+ chargedCents: number;
1995
+ monthlyCents: number;
1996
+ }
1997
+ export interface DeactivateChannelV2Response {
1998
+ address: string;
1999
+ type: ActivatableChannel;
2000
+ /** Every entry of the address after the change. */
2001
+ channels: Array<ChannelEntry>;
2002
+ deactivated: boolean;
2003
+ }
2004
+ export interface SearchNumbersV2Response {
2005
+ items: Array<AvailablePhoneNumber>;
2006
+ }
2007
+ export interface PurchaseNumberV2Response {
2008
+ number: OwnedPhoneNumber;
2009
+ /** The entries of the new number (`sms`, once routed). */
2010
+ channels: Array<ChannelEntry>;
2011
+ /**
2012
+ * Present only when the purchase succeeded and turning SMS on did not.
2013
+ * `details.recommendation` says how to retry.
2014
+ */
2015
+ setupError?: ErrorBody;
2016
+ }
2017
+ export interface ConnectAgentChannelV2Body {
2018
+ address: string;
2019
+ type: ChannelType;
2020
+ }
2021
+ export interface ConnectAgentChannelV2Response {
2022
+ agent: Agent;
2023
+ }
2024
+ export interface ListEmailDomainsV2Response {
2025
+ items: Array<EmailDomain>;
2026
+ }
2027
+ export interface AddEmailDomainV2Body {
2028
+ domain: string;
2029
+ }
2030
+ export interface AddEmailDomainV2Response {
2031
+ domain: EmailDomain;
2032
+ }
2033
+ export interface GetEmailDomainV2Response {
2034
+ domain: EmailDomain;
2035
+ }
2036
+ export interface VerifyEmailDomainV2Response {
2037
+ domain: EmailDomain;
2038
+ }
2039
+ export interface CancelCampaignV2Response {
2040
+ campaign: Broadcast;
2041
+ }
2042
+ export interface ListFunctionsV2Response {
2043
+ items: Array<ZavuFunction>;
2044
+ nextCursor: string | null;
2045
+ }
2046
+ export interface GetFunctionV2Response {
2047
+ function: ZavuFunction;
2048
+ }
2049
+ export interface UpdateFunctionV2Response {
2050
+ function: ZavuFunction;
2051
+ }
2052
+ /** Params for `messages.send`. */
2053
+ export interface MessagesSendParams extends SendMessageRequest {
2054
+ }
2055
+ /** Params for `messages.list`. */
2056
+ export interface MessagesListParams {
2057
+ status?: ListMessagesV2Status;
2058
+ to?: string;
2059
+ channel?: ChannelType;
2060
+ /** @defaultValue `50` */
2061
+ limit?: number;
2062
+ /** Opaque `nextCursor` from the previous page. */
2063
+ cursor?: string;
2064
+ }
2065
+ /** Params for `conversations.list`. */
2066
+ export interface ConversationsListParams {
2067
+ /** Only threads that have carried this transport. */
2068
+ channel?: ChannelType;
2069
+ /**
2070
+ * Keep only threads last handled from this address. Resolved like `from` on `POST
2071
+ * /v2/messages`, narrowed by `channel` when given.
2072
+ */
2073
+ from?: string;
2074
+ /** Identity search (number, email, username). Never message bodies. */
2075
+ search?: string;
2076
+ /** @defaultValue `50` */
2077
+ limit?: number;
2078
+ /** Opaque `nextCursor` from the previous page. */
2079
+ cursor?: string;
2080
+ }
2081
+ /** Params for `conversations.listMessages`. */
2082
+ export interface ConversationsListMessagesParams {
2083
+ /** @defaultValue `50` */
2084
+ limit?: number;
2085
+ /** Opaque `nextCursor` from the previous page. */
2086
+ cursor?: string;
2087
+ }
2088
+ /** Params for `contacts.list`. */
2089
+ export interface ContactsListParams {
2090
+ search?: string;
2091
+ tag?: Array<string>;
2092
+ /** @defaultValue `50` */
2093
+ limit?: number;
2094
+ /** Opaque `nextCursor` from the previous page. */
2095
+ cursor?: string;
2096
+ }
2097
+ /** Params for `contacts.create`. */
2098
+ export interface ContactsCreateParams extends ContactCreateRequest {
2099
+ }
2100
+ /** Params for `contacts.update`. */
2101
+ export interface ContactsUpdateParams extends ContactUpdateRequest {
2102
+ }
2103
+ /** Params for `channels.list`. */
2104
+ export interface ChannelsListParams {
2105
+ /** @defaultValue `50` */
2106
+ limit?: number;
2107
+ /** Opaque `nextCursor` from the previous page. */
2108
+ cursor?: string;
2109
+ }
2110
+ /** Params for `channels.connect`. */
2111
+ export type ChannelsConnectParams = ChannelConnectRequest;
2112
+ /** Params for `templates.list`. */
2113
+ export interface TemplatesListParams {
2114
+ /** @defaultValue `50` */
2115
+ limit?: number;
2116
+ /** Opaque `nextCursor` from the previous page. */
2117
+ cursor?: string;
2118
+ }
2119
+ /** Params for `templates.create`. */
2120
+ export interface TemplatesCreateParams extends TemplateCreateRequest {
2121
+ }
2122
+ /** Params for `templates.submit`. */
2123
+ export interface TemplatesSubmitParams extends TemplateSubmitRequest {
2124
+ }
2125
+ /** Params for `campaigns.list`. */
2126
+ export interface CampaignsListParams {
2127
+ status?: BroadcastStatus;
2128
+ /** @defaultValue `50` */
2129
+ limit?: number;
2130
+ /** Opaque, from a previous `nextCursor`. */
2131
+ cursor?: string;
2132
+ }
2133
+ /** Params for `campaigns.create`. */
2134
+ export interface CampaignsCreateParams extends BroadcastCreateRequest {
2135
+ }
2136
+ /** Params for `campaigns.send`. */
2137
+ export interface CampaignsSendParams extends BroadcastSendRequest {
2138
+ }
2139
+ /** Params for `campaigns.recipients.add`. */
2140
+ export interface CampaignsRecipientsAddParams extends BroadcastContactsAddRequest {
2141
+ }
2142
+ /** Params for `webhook.set`. */
2143
+ export interface WebhookSetParams extends ProjectWebhookV2Put {
2144
+ }
2145
+ /** Params for `agents.list`. */
2146
+ export interface AgentsListParams {
2147
+ /** @defaultValue `50` */
2148
+ limit?: number;
2149
+ /** Opaque `nextCursor` from the previous page. */
2150
+ cursor?: string;
2151
+ }
2152
+ /** Params for `agents.create`. */
2153
+ export interface AgentsCreateParams extends AgentCreateStandaloneRequest {
2154
+ }
2155
+ /** Params for `agents.update`. */
2156
+ export interface AgentsUpdateParams extends AgentUpdateRequest {
2157
+ }
2158
+ /** Params for `agents.test`. */
2159
+ export interface AgentsTestParams extends AgentTestRequest {
2160
+ }
2161
+ /** Params for `agents.channels.connect`. */
2162
+ export interface AgentsChannelsConnectParams extends ConnectAgentChannelV2Body {
2163
+ }
2164
+ /** Params for `numbers.searchAvailable`. */
2165
+ export interface NumbersSearchAvailableParams {
2166
+ countryCode: string;
2167
+ type?: PhoneNumberType;
2168
+ contains?: string;
2169
+ capabilities?: string;
2170
+ /** @defaultValue `10` */
2171
+ limit?: number;
2172
+ }
2173
+ /** Params for `numbers.purchase`. */
2174
+ export interface NumbersPurchaseParams extends PhoneNumberPurchaseRequest {
2175
+ }
2176
+ /** Params for `emailDomains.create`. */
2177
+ export interface EmailDomainsCreateParams extends AddEmailDomainV2Body {
2178
+ }
2179
+ /** Params for `functions.list`. */
2180
+ export interface FunctionsListParams {
2181
+ /** @defaultValue `50` */
2182
+ limit?: number;
2183
+ cursor?: string;
2184
+ }
2185
+ /** Params for `functions.update`. */
2186
+ export interface FunctionsUpdateParams extends FunctionUpdateRequest {
2187
+ }
2188
+ //# sourceMappingURL=types.d.mts.map