@zavudev/sdk 0.58.0 → 0.59.0

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 -1
  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 +8 -4
  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 +2412 -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 +8 -4
  38. package/types.d.mts.map +1 -1
  39. package/types.d.ts +8 -4
  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 +2171 -0
  194. package/v2/types.d.mts.map +1 -0
  195. package/v2/types.d.ts +2171 -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,2171 @@
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. Present on
955
+ * inbound messages that quote an earlier message. Omitted when the quoted message
956
+ * is not found in Zavu (e.g. an old or unknown message) — use
957
+ * replyToProviderMessageId in that case.
958
+ */
959
+ replyToMessageId?: string;
960
+ /**
961
+ * Provider message ID (WhatsApp WAMID) of the quoted message. Present whenever an
962
+ * inbound message is a reply, even if the quoted message is not stored in Zavu.
963
+ */
964
+ replyToProviderMessageId?: string;
965
+ /** Sender of the quoted message (phone number in E.164 format). */
966
+ replyToFrom?: string;
967
+ /**
968
+ * Truncated snippet of the quoted message's text, for display. Empty when the
969
+ * quoted message has no text (e.g. media).
970
+ */
971
+ replyToText?: string;
972
+ /** Type of the quoted message (text, image, video, etc.). */
973
+ replyToMessageType?: string;
974
+ /** Template ID for template messages. */
975
+ templateId?: string;
976
+ /**
977
+ * Variables for body placeholders. Key them to match the template body: by
978
+ * position (`1`, `2`, ...) for positional templates, or by name (e.g.
979
+ * `customer_name`) for named templates. Zavu detects the template's format and
980
+ * sends the correct payload to Meta. Named keys also resolve a named text-header
981
+ * variable. Do not mix positional and named keys in the same request.
982
+ */
983
+ templateVariables?: {
984
+ [key: string]: string;
985
+ };
986
+ /**
987
+ * Variables for dynamic button placeholders (URL buttons and OTP buttons). Keys
988
+ * are the button index (0, 1, 2) in the template's `buttons` array — not the
989
+ * placeholder name. Values substitute the `{{1}}` placeholder inside that button's
990
+ * URL.
991
+ *
992
+ * **WhatsApp constraints:**
993
+ * - URL buttons only accept `{{1}}` — positional, numeric, no whitespace, no
994
+ * name. Named placeholders like `{{token}}` are stored as literal URL text by
995
+ * Meta and cannot be substituted.
996
+ * - At most one placeholder per URL button.
997
+ * - A template may have at most three buttons.
998
+ * - Static URL buttons (no placeholder) and `quick_reply` buttons are not included
999
+ * here.
1000
+ */
1001
+ templateButtonVariables?: {
1002
+ [key: string]: string;
1003
+ };
1004
+ /**
1005
+ * Value for a text-header variable, keyed by `1` (WhatsApp text headers allow at
1006
+ * most one variable). Optional override. If omitted, Zavu resolves the header from
1007
+ * `templateVariables` using the header placeholder's name (e.g. `novios`). Static
1008
+ * text headers need no value.
1009
+ */
1010
+ templateHeaderVariables?: {
1011
+ [key: string]: string;
1012
+ };
1013
+ referral?: AdReferral;
1014
+ }
1015
+ export interface MessageContentContactsItem {
1016
+ name?: string;
1017
+ phones?: Array<string>;
1018
+ }
1019
+ export interface MessageContentButtonsItem {
1020
+ id: string;
1021
+ title: string;
1022
+ }
1023
+ export interface MessageContentSectionsItem {
1024
+ title: string;
1025
+ rows: Array<MessageContentSectionsItemRowsItem>;
1026
+ }
1027
+ export interface MessageContentSectionsItemRowsItem {
1028
+ id: string;
1029
+ title: string;
1030
+ description?: string;
1031
+ }
1032
+ export type MessageContentCtaHeaderType = 'text' | 'image' | 'video' | 'document';
1033
+ export type MessageStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'read' | 'failed' | 'received' | 'pending_url_verification';
1034
+ /**
1035
+ * Type of message. Every type except `text` and `template` is sent on WhatsApp
1036
+ * only: the send routes them there whatever `channel` says, and in v2 an explicit
1037
+ * `channel` other than `whatsapp` is refused with `400` naming `messageType` and
1038
+ * `channel`.
1039
+ *
1040
+ * `location_request` asks the recipient to share their location and is
1041
+ * WhatsApp-only. It takes no `content` object — the prompt goes in `text` (max
1042
+ * 1024 characters) and the button label is fixed by WhatsApp. The recipient's
1043
+ * answer arrives as an inbound `location` message whose `content.replyToMessageId`
1044
+ * is the ID of the request.
1045
+ *
1046
+ * `request_contact_info` asks the recipient to share their phone number and is
1047
+ * WhatsApp-only. Like `location_request` it takes no `content` object — the
1048
+ * prompt goes in `text` (max 1024 characters) and WhatsApp renders a fixed **Share
1049
+ * Contact Info** button. The answer arrives as an inbound `contact` message. Use
1050
+ * it to recover the phone number of a contact who adopted a WhatsApp username and
1051
+ * is only known by their business-scoped user ID (BSUID); when they share it, Zavu
1052
+ * automatically links the phone number to that contact.
1053
+ */
1054
+ export type MessageType = 'text' | 'image' | 'video' | 'audio' | 'document' | 'sticker' | 'location' | 'contact' | 'buttons' | 'list' | 'cta_url' | 'request_contact_info' | 'location_request' | 'reaction' | 'template';
1055
+ export interface OwnedPhoneNumber {
1056
+ id: string;
1057
+ phoneNumber: string;
1058
+ /** Optional custom name for the phone number. */
1059
+ name?: string;
1060
+ capabilities: Array<string>;
1061
+ status: PhoneNumberStatus;
1062
+ pricing: OwnedPhoneNumberPricing;
1063
+ /**
1064
+ * Regulatory review state. Numbers that need no review are `approved` immediately.
1065
+ * A number bought with regulatory information is owned and billed from purchase
1066
+ * and starts `pending_review`; it cannot send messages or place calls until this
1067
+ * is `approved`, and its `channels` entry can be absent until then. The state is
1068
+ * re-checked every 6 hours.
1069
+ */
1070
+ regulatoryStatus: OwnedPhoneNumberRegulatoryStatus;
1071
+ nextRenewalDate?: string;
1072
+ createdAt: string;
1073
+ updatedAt?: string;
1074
+ }
1075
+ export type OwnedPhoneNumberRegulatoryStatus = 'approved' | 'pending_review' | 'rejected';
1076
+ export interface OwnedPhoneNumberPricing {
1077
+ /** Monthly price in USD. */
1078
+ monthlyPrice?: number;
1079
+ /** One-time purchase cost in cents. */
1080
+ upfrontCost?: number;
1081
+ /** Monthly cost in cents. */
1082
+ monthlyCost?: number;
1083
+ /** Whether this is a free number. */
1084
+ isFreeNumber?: boolean;
1085
+ }
1086
+ export interface PhoneNumberCapabilities {
1087
+ sms?: boolean;
1088
+ voice?: boolean;
1089
+ mms?: boolean;
1090
+ }
1091
+ export interface PhoneNumberPricing {
1092
+ /** Monthly price in USD. */
1093
+ monthlyPrice?: number;
1094
+ /** One-time purchase price in USD. */
1095
+ upfrontPrice?: number;
1096
+ /**
1097
+ * Whether this number qualifies as the plan-included number: a US or Canadian
1098
+ * number (a +1 number) costing $20 a month or less. The benefit is one per
1099
+ * account: it is never offered again once claimed, not even after the number is
1100
+ * released.
1101
+ */
1102
+ isFreeEligible?: boolean;
1103
+ }
1104
+ export interface PhoneNumberPurchaseRequest {
1105
+ /** Phone number in E.164 format. */
1106
+ phoneNumber: string;
1107
+ /** Optional custom name for the phone number. */
1108
+ name?: string;
1109
+ /**
1110
+ * Type the number was found under in `GET /v2/numbers/available`. Used to look the
1111
+ * number up and to keep regulatory information for reuse. Required when
1112
+ * `regulatoryRequirements` is sent. `toll_free` is accepted as an alias of
1113
+ * `tollFree`. A number not listed under this type is refused with `400
1114
+ * number_unavailable` saying so.
1115
+ */
1116
+ type?: PhoneNumberType;
1117
+ /**
1118
+ * Regulatory information, for numbers whose requirements list is not empty. Get
1119
+ * the list with `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one
1120
+ * entry per requirement id, except `action` requirements, which take no value.
1121
+ * Every required id must be present, once, and no unknown id may be sent;
1122
+ * otherwise the purchase is refused with `400 invalid_request` before anything is
1123
+ * charged.
1124
+ *
1125
+ * The information is kept for your project under the number's country and `type`.
1126
+ * A later purchase there may omit this field if what is kept still covers that
1127
+ * number's requirements. Omit it for numbers without requirements.
1128
+ */
1129
+ regulatoryRequirements?: Array<PhoneNumberPurchaseRequestRegulatoryRequirementsItem>;
1130
+ }
1131
+ export interface PhoneNumberPurchaseRequestRegulatoryRequirementsItem {
1132
+ /**
1133
+ * A `requirementTypes[].id` from `GET /v1/phone-numbers/requirements`. Each id may
1134
+ * appear only once.
1135
+ */
1136
+ requirementType: string;
1137
+ /**
1138
+ * Depends on the requirement's `type`: the text itself for `textual`; for
1139
+ * `address`, the `id` of an address created in this project with `POST
1140
+ * /v1/addresses`; for `document`, the `id` of a document created with `POST
1141
+ * /v1/documents`. An address or document from another project, or one rejected in
1142
+ * review, is refused.
1143
+ */
1144
+ fieldValue: string;
1145
+ }
1146
+ /**
1147
+ * Billing state of an owned number, separate from `regulatoryStatus`. `pending` is
1148
+ * legacy and is not written to numbers today.
1149
+ */
1150
+ export type PhoneNumberStatus = 'active' | 'suspended' | 'pending' | 'releasing' | 'released';
1151
+ /**
1152
+ * Type of phone number. `mobile` is stocked in countries where no geographic
1153
+ * (`local`) or non-geographic (`national`) inventory exists, and in several
1154
+ * markets it is the only type that can receive SMS.
1155
+ */
1156
+ export type PhoneNumberType = 'local' | 'national' | 'tollFree' | 'mobile';
1157
+ /**
1158
+ * The one webhook for everything in the project. Stored apart from the /v1 project
1159
+ * webhook (`/v1/invitations/webhook`); neither API reads or writes the other's.
1160
+ */
1161
+ export interface ProjectWebhookV2 {
1162
+ url: string;
1163
+ /**
1164
+ * Any event in `WebhookEvent`, including `message.*`, `conversation.new` and
1165
+ * `call.*`.
1166
+ */
1167
+ events: Array<WebhookEvent>;
1168
+ active: boolean;
1169
+ signatureVersion: WebhookSignatureVersion;
1170
+ /**
1171
+ * Returned only by `PUT /v2/webhook` when it creates the webhook, and by `POST
1172
+ * /v2/webhook/secret`.
1173
+ */
1174
+ secret?: string;
1175
+ }
1176
+ export interface ProjectWebhookV2Put {
1177
+ /** HTTPS only. */
1178
+ url: string;
1179
+ /**
1180
+ * Any event in `WebhookEvent`. An unknown value is refused with `400` and
1181
+ * `details.allowed`.
1182
+ */
1183
+ events: Array<WebhookEvent>;
1184
+ /** @defaultValue `true` */
1185
+ active?: boolean;
1186
+ signatureVersion?: WebhookSignatureVersion;
1187
+ /**
1188
+ * Switch off the /v1 sender webhooks of this project in the same call, so each
1189
+ * event arrives once. They are only switched off (`webhookActive: false` on /v1);
1190
+ * URL, events and secret stay, so /v1 can turn one back on. Off by default: the
1191
+ * /v2 webhook is added next to them and both receive every event until you decide.
1192
+ * `senderWebhooks` on the response lists what is still on.
1193
+ *
1194
+ * @defaultValue `false`
1195
+ */
1196
+ disableSenderWebhooks?: boolean;
1197
+ }
1198
+ /**
1199
+ * What the engine decided at send time. Reports only decisions the engine makes;
1200
+ * it does not rank channels by price or by WhatsApp window state.
1201
+ */
1202
+ export interface Routing {
1203
+ channel: ChannelType;
1204
+ /**
1205
+ * The address the message leaves from, as `GET /v2/channels` lists it for
1206
+ * `channel`. With a test-mode key, the WhatsApp sandbox number.
1207
+ */
1208
+ from: string;
1209
+ /**
1210
+ * Why this transport was chosen. Closed list:
1211
+ * - `explicit`: `channel` was given.
1212
+ * - `auto_order`: `channel` omitted or `auto`; the first ACTIVE transport of the
1213
+ * sender in a fixed order (for a phone number: WhatsApp, then SMS, then one-way
1214
+ * SMS). A connected transport that is switched off is skipped, not chosen and
1215
+ * then refused. It does not compare price and does not check the WhatsApp
1216
+ * 24-hour window; a closed window fails later as `message.failed`.
1217
+ * - `conversation`: the sender came from `conversationId` (the sender, not the
1218
+ * transport; the transport is then chosen as for `auto_order` unless `channel`
1219
+ * is given).
1220
+ * - `recipient_type`: `to` is an email address, so email.
1221
+ * - `message_type`: `messageType` is WhatsApp-only (media, interactive,
1222
+ * template...), so WhatsApp.
1223
+ * - `sandbox`: test-mode key, which always uses the WhatsApp sandbox.
1224
+ * An automatic fallback is never a send-time reason: it happens later, see
1225
+ * `Message.attemptedChannels`.
1226
+ */
1227
+ reason: RoutingReason;
1228
+ /**
1229
+ * USD this call took from the balance when it was accepted (rounded to 6
1230
+ * decimals). An estimate: for SMS the delivery report can raise it to the real
1231
+ * cost, and `message.charged` shows where it ended up. Present for `sms` and
1232
+ * `sms_oneway`. Null otherwise — WhatsApp is billed by Meta, email in
1233
+ * 1,000-message blocks, voice per minute — and also null while a message waits
1234
+ * for URL verification, which is charged when it is released. Null means "not
1235
+ * known at send time", not "free".
1236
+ */
1237
+ estimatedCost: number | null;
1238
+ }
1239
+ export type RoutingReason = 'explicit' | 'auto_order' | 'conversation' | 'recipient_type' | 'message_type' | 'sandbox';
1240
+ /**
1241
+ * Request body to send a message. No `Zavu-Sender` header: where it leaves from
1242
+ * comes from `conversationId`, then `from`, then the project default. `to` is
1243
+ * required, except with `conversationId`, where it defaults to whoever the
1244
+ * conversation is with.
1245
+ */
1246
+ export interface SendMessageRequest {
1247
+ /**
1248
+ * Recipient phone number in E.164 format, email address, WhatsApp business-scoped
1249
+ * user ID (BSUID, e.g. `US.13491208655302741918`), or numeric chat ID (for
1250
+ * Telegram/Instagram/Messenger). A phone number written with spaces, dashes, dots
1251
+ * or parentheses after its `+` (`+56 9 1234 5678`) is read as the E.164 number;
1252
+ * bare digits are not (see `400` on this operation). A BSUID is routed to WhatsApp
1253
+ * and sent via the `recipient` field; use it to message a contact who adopted a
1254
+ * username and whose phone number is hidden.
1255
+ *
1256
+ * Required unless `conversationId` is given. With `conversationId` it may be
1257
+ * omitted (it is the conversation's contact: its email for `channel: "email"`,
1258
+ * else the identifier it is filed under); if given it must be one of that
1259
+ * conversation's identifiers (its key, email or BSUID, in any formatting), else
1260
+ * `400` naming `to` and `conversationId`.
1261
+ */
1262
+ to?: string;
1263
+ channel?: ChannelTypeRequest;
1264
+ /**
1265
+ * Type of message. Defaults to 'text'.
1266
+ *
1267
+ * @defaultValue `"text"`
1268
+ */
1269
+ messageType?: MessageType;
1270
+ /** Text body for text messages or caption for media messages. */
1271
+ text?: string;
1272
+ /** Additional content for non-text message types. */
1273
+ content?: MessageContent;
1274
+ /**
1275
+ * Email subject line. Required when channel is 'email' or recipient is an email
1276
+ * address.
1277
+ */
1278
+ subject?: string;
1279
+ /**
1280
+ * HTML body for email messages. If provided, email will be sent as multipart with
1281
+ * both text and HTML.
1282
+ */
1283
+ htmlBody?: string;
1284
+ /** Reply-To email address for email messages. */
1285
+ replyTo?: string;
1286
+ /** Optional idempotency key to avoid duplicate sends. */
1287
+ idempotencyKey?: string;
1288
+ /** Arbitrary metadata to associate with the message. */
1289
+ metadata?: {
1290
+ [key: string]: string;
1291
+ };
1292
+ /**
1293
+ * Whether to enable automatic fallback to SMS if WhatsApp fails. Defaults to true.
1294
+ *
1295
+ * @defaultValue `true`
1296
+ */
1297
+ fallbackEnabled?: boolean;
1298
+ /**
1299
+ * Language code for voice text-to-speech (e.g., 'en-US', 'es-ES', 'pt-BR'). If
1300
+ * omitted, language is auto-detected from recipient's country code.
1301
+ */
1302
+ voiceLanguage?: string;
1303
+ /**
1304
+ * Email attachments. Only supported when channel is 'email'. Maximum 40MB total
1305
+ * size.
1306
+ */
1307
+ attachments?: Array<EmailAttachmentInput>;
1308
+ /**
1309
+ * Which of your addresses sends (see `GET /v2/channels`): an E.164 number in any
1310
+ * common formatting, an email address, `@botname`, `@username`, a Page id.
1311
+ * Resolved inside your project only. Omitted: the project default, the same one
1312
+ * /v1 uses when no `Zavu-Sender` header is sent. Ignored when `conversationId` is
1313
+ * set, and with a test-mode key, which always sends from the WhatsApp sandbox.
1314
+ *
1315
+ * An address that no entry has returns `404 not_found`. An address two of your
1316
+ * senders share (a number whose WhatsApp was connected on one sender and SMS on
1317
+ * another) resolves when `channel` names the transport; otherwise it returns `409
1318
+ * ambiguous_from` with `details.candidates[{address, type, v1SenderId}]`, and in
1319
+ * that case, and only then, `from` also accepts one of those `v1SenderId` values.
1320
+ */
1321
+ from?: string;
1322
+ /**
1323
+ * Reply inside an existing conversation: the message leaves from the sender that
1324
+ * last handled it (`from` on the Conversation), and goes to whoever the
1325
+ * conversation is with, so `to` may be omitted. A `to` that is not the
1326
+ * conversation's contact is refused with `400` (`details.errors` on `to` and
1327
+ * `conversationId`, `details.conversationTo`) instead of silently opening another
1328
+ * conversation. Takes precedence over `from`. When `channel` is omitted,
1329
+ * `routing.reason` is then `conversation`. A conversation of another project
1330
+ * returns `404`; one with no sender recorded returns `409 no_channel`. The 202's
1331
+ * `message.conversationId` is set whenever the conversation the message is filed
1332
+ * in already exists; it is absent only for a recipient's first message, whose
1333
+ * conversation is created after the response. A reply to a conversation that an
1334
+ * inbound email opened reaches the right person but is filed in a separate
1335
+ * conversation keyed by the email address.
1336
+ */
1337
+ conversationId?: string;
1338
+ }
1339
+ export interface SendMessageResponse {
1340
+ message: Message;
1341
+ routing: Routing;
1342
+ }
1343
+ export interface Template {
1344
+ id: string;
1345
+ /** Template name. For WhatsApp, must match the approved template name in Meta. */
1346
+ name: string;
1347
+ /** Language code. */
1348
+ language: string;
1349
+ /**
1350
+ * Default template body with variables: positional ({{1}}, {{2}}) or named
1351
+ * ({{customer_name}}, {{contact.first_name}}). Templates created in Zavu are
1352
+ * submitted to Meta as positional; templates imported from a WhatsApp Business
1353
+ * Account keep their original format (named or positional). Used when no
1354
+ * channel-specific body is set.
1355
+ */
1356
+ body: string;
1357
+ /** Channel-specific body for SMS messages. Falls back to `body` if not set. */
1358
+ smsBody?: string;
1359
+ /** Channel-specific body for Telegram messages. Falls back to `body` if not set. */
1360
+ telegramBody?: string;
1361
+ /** Channel-specific body for Instagram messages. Falls back to `body` if not set. */
1362
+ instagramBody?: string;
1363
+ /**
1364
+ * The category the template is billed under. For a template linked to WhatsApp
1365
+ * this is the category **Meta currently assigns**, not the one it was submitted
1366
+ * with: Meta can recategorize a template at approval or at any point afterwards,
1367
+ * and that changes what the message costs.
1368
+ *
1369
+ * A recategorization reaches this field through the `template.status_changed`
1370
+ * webhook, which carries `data.category`, and through `POST /v1/templates/sync`,
1371
+ * which reconciles it against Meta. Read one of those rather than assuming the
1372
+ * category you sent is the one in force.
1373
+ *
1374
+ * For a template that was never submitted to WhatsApp, this is the category stored
1375
+ * locally, defaulting to `UTILITY`.
1376
+ */
1377
+ category: WhatsAppCategory;
1378
+ /** @defaultValue `"draft"` */
1379
+ status?: TemplateStatus;
1380
+ /** List of variable names for documentation. */
1381
+ variables?: Array<string>;
1382
+ /** Type of header (text, image, video, document). */
1383
+ headerType?: string;
1384
+ /** Header content (text or media URL). */
1385
+ headerContent?: string;
1386
+ /** Footer text for the template. */
1387
+ footer?: string;
1388
+ /** Template buttons. */
1389
+ buttons?: Array<TemplateButtonsItem>;
1390
+ /** Add 'Do not share this code' disclaimer. Only for AUTHENTICATION templates. */
1391
+ addSecurityRecommendation?: boolean;
1392
+ /** Code expiration time in minutes. Only for AUTHENTICATION templates. */
1393
+ codeExpirationMinutes?: number;
1394
+ /** WhatsApp-specific template information. */
1395
+ whatsapp?: TemplateWhatsapp;
1396
+ createdAt?: string;
1397
+ updatedAt?: string;
1398
+ }
1399
+ export type TemplateStatus = 'draft' | 'pending' | 'approved' | 'rejected';
1400
+ export interface TemplateButtonsItem {
1401
+ type?: TemplateButtonsItemType;
1402
+ text?: string;
1403
+ url?: string;
1404
+ /**
1405
+ * Sample value used to substitute `{{1}}` in the URL when submitting the template
1406
+ * to Meta for review. Only present for dynamic URL buttons.
1407
+ */
1408
+ example?: string;
1409
+ phoneNumber?: string;
1410
+ /** OTP button type. Required when type is 'otp'. */
1411
+ otpType?: TemplateButtonsItemOtpType;
1412
+ /** Android package name. Required for ONE_TAP buttons. */
1413
+ packageName?: string;
1414
+ /** Android app signature hash. Required for ONE_TAP buttons. */
1415
+ signatureHash?: string;
1416
+ }
1417
+ export type TemplateButtonsItemType = 'quick_reply' | 'url' | 'phone' | 'otp' | 'request_contact_info';
1418
+ export type TemplateButtonsItemOtpType = 'COPY_CODE' | 'ONE_TAP';
1419
+ export interface TemplateWhatsapp {
1420
+ /** WhatsApp template name. */
1421
+ templateName?: string;
1422
+ /** WhatsApp Business Account namespace. */
1423
+ namespace?: string;
1424
+ /** WhatsApp approval status. */
1425
+ status?: string;
1426
+ }
1427
+ export interface TemplateCreateRequest {
1428
+ name: string;
1429
+ /** @defaultValue `"en"` */
1430
+ language: string;
1431
+ /** Default template body. Used when no channel-specific body is set. */
1432
+ body: string;
1433
+ /** Channel-specific body for SMS. Falls back to `body` if not set. */
1434
+ smsBody?: string;
1435
+ /** Channel-specific body for Telegram. Falls back to `body` if not set. */
1436
+ telegramBody?: string;
1437
+ /** Channel-specific body for Instagram. Falls back to `body` if not set. */
1438
+ instagramBody?: string;
1439
+ whatsappCategory?: WhatsAppCategory;
1440
+ /** Type of header for the template. */
1441
+ headerType?: TemplateCreateRequestHeaderType;
1442
+ /** Header content (text string or media URL). */
1443
+ headerContent?: string;
1444
+ /** Footer text for the template. */
1445
+ footer?: string;
1446
+ variables?: Array<string>;
1447
+ /** Template buttons (max 3). */
1448
+ buttons?: Array<TemplateCreateRequestButtonsItem>;
1449
+ /** Add 'Do not share this code' disclaimer. Only for AUTHENTICATION templates. */
1450
+ addSecurityRecommendation?: boolean;
1451
+ /** Code expiration time in minutes. Only for AUTHENTICATION templates. */
1452
+ codeExpirationMinutes?: number;
1453
+ }
1454
+ export type TemplateCreateRequestHeaderType = 'text' | 'image' | 'video' | 'document';
1455
+ export interface TemplateCreateRequestButtonsItem {
1456
+ /**
1457
+ * `request_contact_info` renders a fixed **Share Contact Info** button that asks
1458
+ * the recipient to share their phone number — useful when a contact adopted a
1459
+ * WhatsApp username and you only know their BSUID. It takes no other fields.
1460
+ */
1461
+ type: TemplateCreateRequestButtonsItemType;
1462
+ /**
1463
+ * Button label. Required for every type except `request_contact_info`, whose label
1464
+ * is fixed by WhatsApp.
1465
+ */
1466
+ text?: string;
1467
+ /**
1468
+ * Button destination. Use `{{1}}` exactly once for a dynamic URL (e.g.
1469
+ * `https://example.com/orders/{{1}}`); WhatsApp only accepts the strict `{{1}}`
1470
+ * form. Static URLs must not contain any `{{...}}` placeholder.
1471
+ */
1472
+ url?: string;
1473
+ /**
1474
+ * Sample value Meta uses to review templates with a dynamic URL button.
1475
+ * Substituted into `{{1}}` of the URL when the template is submitted to Meta. Only
1476
+ * meaningful when `url` contains `{{1}}`; ignored for static URLs.
1477
+ */
1478
+ example?: string;
1479
+ phoneNumber?: string;
1480
+ /**
1481
+ * Required when type is 'otp'. COPY_CODE shows copy button, ONE_TAP enables
1482
+ * Android autofill.
1483
+ */
1484
+ otpType?: TemplateCreateRequestButtonsItemOtpType;
1485
+ /** Android package name. Required for ONE_TAP buttons. */
1486
+ packageName?: string;
1487
+ /** Android app signature hash. Required for ONE_TAP buttons. */
1488
+ signatureHash?: string;
1489
+ }
1490
+ export type TemplateCreateRequestButtonsItemType = 'quick_reply' | 'url' | 'phone' | 'otp' | 'request_contact_info';
1491
+ export type TemplateCreateRequestButtonsItemOtpType = 'COPY_CODE' | 'ONE_TAP';
1492
+ export interface TemplateSubmitRequest {
1493
+ /**
1494
+ * The WhatsApp number whose Business Account receives the template: an address
1495
+ * with a `whatsapp` entry in `GET /v2/channels`.
1496
+ */
1497
+ from: string;
1498
+ category?: WhatsAppCategory;
1499
+ }
1500
+ /**
1501
+ * Type of event that triggers the webhook.
1502
+ *
1503
+ * **Message lifecycle events:**
1504
+ * - `message.queued`: Message created and queued for sending. `data.status` =
1505
+ * `queued`
1506
+ * - `message.sent`: Message accepted by the provider. `data.status` = `sent`
1507
+ * - `message.delivered`: Message delivered to recipient. `data.status` =
1508
+ * `delivered`
1509
+ * - `message.read`: Message was read by the recipient (WhatsApp only).
1510
+ * `data.status` = `read`
1511
+ * - `message.failed`: Message failed to send. `data.status` = `failed`
1512
+ *
1513
+ * **Inbound events:**
1514
+ * - `message.inbound`: New message received from a contact. `data.conversationId`,
1515
+ * the inbox thread id (deep-link with
1516
+ * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`), is sent on
1517
+ * **email** messages only, and is `null` there on the first message of a
1518
+ * brand-new thread. On every other channel it is absent: read it from `GET
1519
+ * /v2/messages/{messageId}`, which always has it, or from `conversation.new` for
1520
+ * a new contact. Reactions are delivered as `message.inbound` with
1521
+ * `messageType='reaction'`. When the contact replied to (quoted) an earlier
1522
+ * message, `data.content` carries the reply context: `replyToMessageId`,
1523
+ * `replyToProviderMessageId`, `replyToFrom`, `replyToText`, and
1524
+ * `replyToMessageType`. `data.providerTimestamp` is the provider's original
1525
+ * receive time in Unix milliseconds (the moment the channel received the message
1526
+ * from the contact — WhatsApp, Telegram, Instagram, Messenger; `null` for SMS
1527
+ * and email). Compare it against the top-level `timestamp` (when Zavu dispatched
1528
+ * the webhook) to detect and ignore delayed deliveries. When the conversation
1529
+ * was opened from a Click-to-WhatsApp ad or post, `data.referral` carries the ad
1530
+ * attribution — including `ctwaClid`, the identifier Meta's Conversions API
1531
+ * needs to credit a conversion back to that ad. WhatsApp only, and only on the
1532
+ * first message of the thread: it is absent from every later message, so persist
1533
+ * it when it arrives.
1534
+ * - `message.unsupported`: Received a message type that is not supported
1535
+ *
1536
+ * **Broadcast events:**
1537
+ * - `broadcast.status_changed`: Broadcast status changed (pending_review,
1538
+ * approved, rejected, sending, completed, cancelled)
1539
+ *
1540
+ * **Other events:**
1541
+ * - `conversation.new`: New conversation started with a contact. `data` carries
1542
+ * `conversationId` (the inbox thread id — deep-link with
1543
+ * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`), the
1544
+ * `phoneNumber` or `email` key, `channel`, `firstMessageId`, `firstMessageText`,
1545
+ * and `profileName`.
1546
+ * - `template.status_changed`: WhatsApp template approval status changed. `data`
1547
+ * carries `templateId`, `name`, `previousStatus`, `currentStatus`,
1548
+ * `rejectionReason`, and `category` — the category Meta currently bills the
1549
+ * template under. Meta can recategorize a template (typically `UTILITY` to
1550
+ * `MARKETING`) at approval or long afterwards, which changes what each message
1551
+ * costs; `category` is how that reaches you. A recategorization with no status
1552
+ * change is delivered as this same event, so compare `category` against what you
1553
+ * hold rather than only reacting to `currentStatus`.
1554
+ *
1555
+ * **Partner events:**
1556
+ * - `invitation.status_changed`: A partner invitation's stored status changed: to
1557
+ * `in_progress`, `completed`, `failed`, `cancelled`, or back to `pending` when
1558
+ * it is resent from the dashboard. A change to the same status sends nothing,
1559
+ * and expiry is not a stored change, so no event is sent when an invitation
1560
+ * expires. Delivered to the project that created the invitation; a parent
1561
+ * project does not receive its sub-accounts' events. `data` carries
1562
+ * `invitationId`, `clientName`, `clientEmail`, `connectionType` (`whatsapp_waba`
1563
+ * or `messenger`), `previousStatus`, and `currentStatus`. On `completed` it also
1564
+ * carries `connectedAccount` (`channel`, `id`, `name`), the WhatsApp number or
1565
+ * Facebook Page that was linked, and, for WhatsApp, `wabaAccountId`. On `failed`
1566
+ * it carries `failureReason`; the invitation link stays usable, so a client can
1567
+ * retry it.
1568
+ *
1569
+ * **Voice Agent events:**
1570
+ * For every voice event, `data` carries `callId`, `direction`, `from`, `to`,
1571
+ * `status`, `durationSeconds`, `endReason`, and `transcriptAvailable`. The
1572
+ * terminal events (`call.completed`, `call.failed`) additionally carry `cost` —
1573
+ * what the call was billed, in USD, combining telephony and the managed voice
1574
+ * pipeline — and `currency`. They are dispatched after the call is charged, so
1575
+ * `cost` is populated rather than zero; telephony can still be settling on an
1576
+ * outbound call, in which case `GET /v1/calls/{callId}` holds the reconciled
1577
+ * figure.
1578
+ * - `call.initiated`: An outbound call was created and is dialing, or an inbound
1579
+ * call was received. `data.status` = `ringing`
1580
+ * - `call.answered`: The call was answered and the voice agent is connected.
1581
+ * `data.status` = `in_progress`
1582
+ * - `call.completed`: The call ended after a conversation. `data.status` =
1583
+ * `completed`; `durationSeconds` and `endReason` describe how it ended, and
1584
+ * `transcriptAvailable` indicates whether a transcript can be fetched.
1585
+ * - `call.failed`: The call could not be completed (busy, no answer, canceled, or
1586
+ * an error). `data.status` is the terminal status and `endReason` explains the
1587
+ * cause.
1588
+ *
1589
+ * **Custom domain events:**
1590
+ * - `domain.verified`: A custom email domain passed verification (DKIM, and
1591
+ * SPF/DMARC/MAIL FROM if enhanced records are enabled)
1592
+ * - `domain.failed`: A custom email domain failed verification or is partially
1593
+ * verified
1594
+ */
1595
+ 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';
1596
+ /**
1597
+ * Data payload for message webhook events (queued, sent, delivered, failed,
1598
+ * inbound).
1599
+ */
1600
+ export interface WebhookMessageData {
1601
+ /** ID of the message. */
1602
+ messageId: string;
1603
+ /**
1604
+ * Recipient phone number or email. On `message.inbound` this is your own number
1605
+ * (the message's destination).
1606
+ */
1607
+ to: string;
1608
+ /**
1609
+ * Sender of the message. Present on `message.inbound`: the contact who sent the
1610
+ * message.
1611
+ */
1612
+ from?: string;
1613
+ channel: ChannelType;
1614
+ status: MessageStatus;
1615
+ /** Type of the message. Present on `message.inbound`. */
1616
+ messageType?: MessageType;
1617
+ /**
1618
+ * ID of the conversation (inbox thread) this message belongs to. Sent on
1619
+ * `message.inbound` for **email** messages only; on SMS, WhatsApp, Telegram,
1620
+ * Instagram and Messenger it is absent. Use it to deep-link to the dashboard
1621
+ * inbox: `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`. On
1622
+ * email it is `null` on the first message of a brand-new thread. In every case,
1623
+ * fetch it via `GET /v2/messages/{messageId}`, whose `conversationId` is always
1624
+ * populated, or take it from the `conversation.new` event for a new contact.
1625
+ */
1626
+ conversationId?: string | null;
1627
+ /**
1628
+ * Text body or media caption. Present on `message.inbound` when the message has
1629
+ * text.
1630
+ */
1631
+ text?: string;
1632
+ /** Error code if the message failed. */
1633
+ errorCode?: string | null;
1634
+ /** Error message if the message failed. */
1635
+ errorMessage?: string | null;
1636
+ /**
1637
+ * The provider's original receive time in Unix milliseconds (when the channel
1638
+ * received the message from the contact). Present on `message.inbound` for
1639
+ * channels that report it (WhatsApp, Telegram, Instagram, Messenger); null for SMS
1640
+ * and email.
1641
+ */
1642
+ providerTimestamp?: number | null;
1643
+ /**
1644
+ * Click-to-WhatsApp ad attribution. Present on `message.inbound` only when this is
1645
+ * the first message of a conversation opened from a Meta ad or post — absent on
1646
+ * every later message in that same thread, and on organic conversations. Read
1647
+ * `referral.ctwaClid` here to attribute the conversation, and persist it on your
1648
+ * side: this webhook is the only delivery. `GET /v2/messages/{messageId}` also
1649
+ * returns it, under `content.referral`.
1650
+ */
1651
+ referral?: AdReferral;
1652
+ }
1653
+ /**
1654
+ * What a `POST` to your /v2 webhook carries. Signed like every Zavu webhook
1655
+ * (`X-Zavu-Signature`, with the webhook's `signatureVersion`); the event name is
1656
+ * also in the `X-Zavu-Event` header. No sender id appears anywhere in it.
1657
+ */
1658
+ export interface WebhookPayloadV2 {
1659
+ /**
1660
+ * Unique event identifier. Different from the id of the same event delivered to a
1661
+ * /v1 webhook.
1662
+ */
1663
+ id: string;
1664
+ event: WebhookEvent;
1665
+ /** Unix milliseconds when the event was created. */
1666
+ timestamp: number;
1667
+ projectId: string;
1668
+ /**
1669
+ * Where the event's message or call came from. Outbound message events: your
1670
+ * address. `message.inbound`, `message.unsupported`, `conversation.new`: the
1671
+ * contact. `call.*`: the caller. Project-level events (`invitation.*`, `domain.*`,
1672
+ * `broadcast.*`) are not about one address: read `data`. On those, `from`, `to`
1673
+ * and `type` can be null, or name an address of the channel group the event was
1674
+ * recorded on.
1675
+ */
1676
+ from: string | null;
1677
+ /**
1678
+ * The other end: the recipient of an outbound message, your address for an inbound
1679
+ * one, the callee of a call.
1680
+ */
1681
+ to: string | null;
1682
+ /** The transport, as in `GET /v2/channels`. Null when the event names none. */
1683
+ type: ChannelType | null;
1684
+ /** The same event data /v1 sends (see `WebhookEvent`), without `senderId`. */
1685
+ data: {
1686
+ [key: string]: unknown;
1687
+ };
1688
+ }
1689
+ /**
1690
+ * Which `X-Zavu-Signature` scheme this receiver is sent. The header is `t=<unix
1691
+ * seconds>` followed by the signatures.
1692
+ *
1693
+ * - `v1`: `v1=HMAC_SHA256(secret, body)`.
1694
+ * - `v2`: `v2=HMAC_SHA256(secret, "{t}.{body}")`. The current scheme, and the
1695
+ * default for a new /v2 webhook. It signs the timestamp together with the body.
1696
+ * - `v1+v2`: both signatures, sharing one `t`. The migration setting: a receiver
1697
+ * reading either one works.
1698
+ *
1699
+ * Moving straight between `v1` and `v2`, in either direction, returns `400`. Set
1700
+ * `v1+v2` first. See
1701
+ * https://docs.zavu.dev/guides/receiving-messages/signature-migration
1702
+ */
1703
+ export type WebhookSignatureVersion = 'v1' | 'v1+v2' | 'v2';
1704
+ /** WhatsApp template category. */
1705
+ export type WhatsAppCategory = 'UTILITY' | 'MARKETING' | 'AUTHENTICATION';
1706
+ /** One place the project can send from, on one transport. */
1707
+ export interface ChannelEntry {
1708
+ /**
1709
+ * The address the recipient sees: an E.164 number (`sms`, `voice`, `whatsapp`), an
1710
+ * email address (lowercase), `@botname` (`telegram`), `@username` (`instagram`),
1711
+ * the Facebook Page id (`messenger`), or the literal `sms_oneway` (one-way SMS
1712
+ * goes out from shared system numbers, and messages on it store this same literal
1713
+ * as `from`).
1714
+ */
1715
+ address: string;
1716
+ type: ChannelType;
1717
+ /**
1718
+ * It can send right now. A connected transport that is switched off is listed with
1719
+ * `active: false`; turn it on with `POST /v2/channels/{address}/{type}/activate`.
1720
+ * `sms`, `sms_oneway` and `voice` have no switch and are always active.
1721
+ */
1722
+ active: boolean;
1723
+ /**
1724
+ * Read-only. The /v1 sender behind this entry, usable as the `Zavu-Sender` header
1725
+ * on /v1. Entries with the same `v1SenderId` are one channel group. On /v2 it is
1726
+ * accepted as `from` only when two entries of different groups share an address
1727
+ * (see `409 ambiguous_from`).
1728
+ */
1729
+ v1SenderId: string;
1730
+ }
1731
+ /**
1732
+ * A /v1 sender webhook that is still on. Each one also receives the events it is
1733
+ * subscribed to, as a separate delivery.
1734
+ */
1735
+ export interface SenderWebhookV1 {
1736
+ /** The sender's first address; null for a sender with no connected transport. */
1737
+ address: string | null;
1738
+ url: string;
1739
+ /** Read-only; the sender to change on /v1. */
1740
+ v1SenderId: string;
1741
+ }
1742
+ /**
1743
+ * What to connect. Only channels that need no purchase and no third-party signup
1744
+ * are connected here: one-way SMS, an email address at a verified domain, a
1745
+ * Telegram bot. Two-way SMS and voice come with a number (`POST /v2/numbers`);
1746
+ * WhatsApp, Instagram and Messenger connect through Meta, from Accounts in the
1747
+ * dashboard. Any of those types here is a `400` saying so.
1748
+ */
1749
+ export type ChannelConnectRequest = ChannelConnectRequestSmsOneway | ChannelConnectRequestEmail | ChannelConnectRequestTelegram;
1750
+ export interface EmailDomain {
1751
+ id: string;
1752
+ domain: string;
1753
+ /** Overall verification status. */
1754
+ status: string;
1755
+ dkimStatus: string;
1756
+ /**
1757
+ * DNS records to publish. Present when fetching a single domain or after adding
1758
+ * one.
1759
+ */
1760
+ dnsRecords?: Array<EmailDomainDnsRecord>;
1761
+ /**
1762
+ * Present with `dnsRecords`. False when the DKIM records could not be generated:
1763
+ * such a domain cannot verify whatever DNS you publish, and `setupError` says what
1764
+ * to do.
1765
+ */
1766
+ verifiable?: boolean;
1767
+ /**
1768
+ * Present when `verifiable` is false. `recommendation` is the same everywhere this
1769
+ * domain is refused (`POST .../verify`, `POST /v2/channels`): remove the domain
1770
+ * and add it again, which sets it up from scratch; contact support if the new one
1771
+ * has no `dkim` record either. It never says to retry verify or to publish the
1772
+ * other records.
1773
+ */
1774
+ setupError?: EmailDomainSetupError;
1775
+ }
1776
+ export interface EmailDomainSetupError {
1777
+ code?: 'dkim_records_unavailable';
1778
+ message?: string;
1779
+ recommendation?: string;
1780
+ }
1781
+ export interface EmailDomainDnsRecord {
1782
+ /** DNS record type. */
1783
+ type: string;
1784
+ /** Record host/name to create. */
1785
+ name: string;
1786
+ /** Record value. */
1787
+ value: string;
1788
+ /** Priority (MX records only). */
1789
+ priority?: number;
1790
+ /** What the record is for. */
1791
+ purpose: EmailDomainDnsRecordPurpose;
1792
+ /**
1793
+ * Whether the record is required to verify + send (DKIM) or recommended for
1794
+ * deliverability.
1795
+ */
1796
+ required: boolean;
1797
+ }
1798
+ export type EmailDomainDnsRecordPurpose = 'dkim' | 'spf' | 'dmarc' | 'mail_from';
1799
+ /**
1800
+ * A Zavu Function: TypeScript that runs in Zavu Cloud, either reacting to events,
1801
+ * serving HTTP, or holding the agents its code declares.
1802
+ */
1803
+ export interface ZavuFunction {
1804
+ id: string;
1805
+ slug: string;
1806
+ name: string;
1807
+ description?: string | null;
1808
+ runtime: string;
1809
+ status: FunctionStatus;
1810
+ /**
1811
+ * True only while a version is live and not paused (`status: active`). A draft, a
1812
+ * failed first deploy, a deploy in progress or a pause are all `false`.
1813
+ */
1814
+ enabled: boolean;
1815
+ timeoutSec: number;
1816
+ memoryMb: FunctionMemoryMb;
1817
+ /**
1818
+ * arm64 is the default and the cheaper one; x86_64 bills each invocation at 1.25x
1819
+ * units. Applied on the next deploy.
1820
+ */
1821
+ architecture: FunctionArchitecture;
1822
+ httpEnabled: boolean;
1823
+ /** Null while `httpEnabled` is false: the URL does not serve then. */
1824
+ publicUrl?: string | null;
1825
+ activeDeploymentId?: string | null;
1826
+ createdAt: string;
1827
+ updatedAt: string;
1828
+ /**
1829
+ * The customer paused it. A deploy, a git push or a rollback does not resume it.
1830
+ * Pausing stops event triggers; the HTTP endpoint has its own switch,
1831
+ * `httpEnabled`, and the tools of the agents it declares keep answering.
1832
+ */
1833
+ paused: boolean;
1834
+ }
1835
+ export type FunctionStatus = 'draft' | 'deploying' | 'active' | 'failed' | 'disabled';
1836
+ export type FunctionMemoryMb = 128 | 256 | 512 | 1024;
1837
+ export type FunctionArchitecture = 'arm64' | 'x86_64';
1838
+ /**
1839
+ * Configuration only, applied in one transaction: if any part is refused, nothing
1840
+ * changes. Code, dependencies and deploys are on /v1 (`PATCH
1841
+ * /v1/functions/{functionId}` and `POST /v1/functions/{functionId}/deploy`). Send
1842
+ * at least one field. Every invalid field is reported in `details.errors`.
1843
+ */
1844
+ export interface FunctionUpdateRequest {
1845
+ name?: string;
1846
+ /** null clears it. */
1847
+ description?: string | null;
1848
+ /** Applied on the next deploy. */
1849
+ timeoutSec?: number;
1850
+ /** Applied on the next deploy. */
1851
+ memoryMb?: FunctionUpdateRequestMemoryMb;
1852
+ architecture?: FunctionUpdateRequestArchitecture;
1853
+ /**
1854
+ * false pauses the function, true resumes it. Refused with 409
1855
+ * `function_not_ready` while it is a draft, deploying, or its first deploy failed.
1856
+ */
1857
+ enabled?: boolean;
1858
+ /**
1859
+ * Switch the public endpoint on or off. Applies to the deployed function without a
1860
+ * redeploy.
1861
+ */
1862
+ httpEnabled?: boolean;
1863
+ }
1864
+ export type FunctionUpdateRequestMemoryMb = 128 | 256 | 512 | 1024;
1865
+ export type FunctionUpdateRequestArchitecture = 'arm64' | 'x86_64';
1866
+ /**
1867
+ * One-way SMS from shared system numbers. No number or credential; recipients
1868
+ * cannot reply. Sends within the SMS daily ceiling. Sending to a US or Canadian
1869
+ * (+1) number needs an approved 10DLC campaign first, and is refused with `403
1870
+ * ten_dlc_required` until then. Refused with `403 kyb_required` only on an account
1871
+ * that must verify its business before using one-way SMS.
1872
+ */
1873
+ export interface ChannelConnectRequestSmsOneway {
1874
+ type: 'sms_oneway';
1875
+ }
1876
+ /**
1877
+ * An address at an email domain of this project that is verified (`GET
1878
+ * /v2/email-domains`).
1879
+ */
1880
+ export interface ChannelConnectRequestEmail {
1881
+ type: 'email';
1882
+ address: string;
1883
+ /** Display name in the recipient's inbox. */
1884
+ fromName?: string;
1885
+ }
1886
+ /** A Telegram bot. Its address is `@botname`. */
1887
+ export interface ChannelConnectRequestTelegram {
1888
+ type: 'telegram';
1889
+ /** Bot token from @BotFather. */
1890
+ botToken: string;
1891
+ }
1892
+ export type ListMessagesV2Status = 'queued' | 'sending' | 'sent' | 'delivered' | 'failed' | 'received';
1893
+ export interface ListMessagesV2Response {
1894
+ items: Array<Message>;
1895
+ nextCursor?: string | null;
1896
+ }
1897
+ export interface GetMessageV2Response {
1898
+ message: Message;
1899
+ }
1900
+ export interface ListConversationsV2Response {
1901
+ items: Array<Conversation>;
1902
+ nextCursor?: string | null;
1903
+ }
1904
+ export interface GetConversationV2Response {
1905
+ conversation: Conversation;
1906
+ }
1907
+ export interface ListConversationMessagesV2Response {
1908
+ items: Array<Message>;
1909
+ nextCursor?: string | null;
1910
+ }
1911
+ export interface MarkConversationReadV2Response {
1912
+ conversation: Conversation;
1913
+ }
1914
+ export interface ListContactsV2Response {
1915
+ items: Array<Contact>;
1916
+ nextCursor?: string | null;
1917
+ }
1918
+ export interface ListChannelsV2Response {
1919
+ items: Array<ChannelEntry>;
1920
+ nextCursor?: string | null;
1921
+ }
1922
+ export interface ConnectChannelV2Response {
1923
+ items: Array<ChannelEntry>;
1924
+ }
1925
+ export interface ListTemplatesV2Response {
1926
+ items: Array<Template>;
1927
+ nextCursor?: string | null;
1928
+ }
1929
+ export interface ListCampaignsV2Response {
1930
+ items: Array<Broadcast>;
1931
+ nextCursor: string | null;
1932
+ }
1933
+ export interface CreateCampaignV2Response {
1934
+ campaign: Broadcast;
1935
+ }
1936
+ export interface GetCampaignV2Response {
1937
+ campaign: Broadcast;
1938
+ }
1939
+ export interface SendCampaignV2Response {
1940
+ campaign: Broadcast;
1941
+ }
1942
+ export interface GetWebhookV2Response {
1943
+ webhook: ProjectWebhookV2 | null;
1944
+ senderWebhooks: Array<SenderWebhookV1>;
1945
+ }
1946
+ export interface PutWebhookV2Response {
1947
+ webhook: ProjectWebhookV2;
1948
+ senderWebhooks: Array<SenderWebhookV1>;
1949
+ /** How many /v1 sender webhooks this call switched off. */
1950
+ disabledSenderWebhooks: number;
1951
+ }
1952
+ export interface RotateWebhookSecretV2Response {
1953
+ secret: string;
1954
+ }
1955
+ export interface ListAgentsV2Response {
1956
+ items: Array<Agent>;
1957
+ nextCursor?: string | null;
1958
+ }
1959
+ export interface CreateAgentV2Response {
1960
+ agent: Agent;
1961
+ }
1962
+ export interface GetAgentV2Response {
1963
+ agent: Agent;
1964
+ }
1965
+ export interface UpdateAgentV2Response {
1966
+ agent: Agent;
1967
+ }
1968
+ export interface GetChannelV2Response {
1969
+ items: Array<ChannelEntry>;
1970
+ }
1971
+ export interface ActivateChannelV2Response {
1972
+ address: string;
1973
+ type: ActivatableChannel;
1974
+ /** Every entry of the address after the change. */
1975
+ channels: Array<ChannelEntry>;
1976
+ activated: boolean;
1977
+ chargedCents: number;
1978
+ monthlyCents: number;
1979
+ }
1980
+ export interface DeactivateChannelV2Response {
1981
+ address: string;
1982
+ type: ActivatableChannel;
1983
+ /** Every entry of the address after the change. */
1984
+ channels: Array<ChannelEntry>;
1985
+ deactivated: boolean;
1986
+ }
1987
+ export interface SearchNumbersV2Response {
1988
+ items: Array<AvailablePhoneNumber>;
1989
+ }
1990
+ export interface PurchaseNumberV2Response {
1991
+ number: OwnedPhoneNumber;
1992
+ /** The entries of the new number (`sms`, once routed). */
1993
+ channels: Array<ChannelEntry>;
1994
+ /**
1995
+ * Present only when the purchase succeeded and turning SMS on did not.
1996
+ * `details.recommendation` says how to retry.
1997
+ */
1998
+ setupError?: ErrorBody;
1999
+ }
2000
+ export interface ConnectAgentChannelV2Body {
2001
+ address: string;
2002
+ type: ChannelType;
2003
+ }
2004
+ export interface ConnectAgentChannelV2Response {
2005
+ agent: Agent;
2006
+ }
2007
+ export interface ListEmailDomainsV2Response {
2008
+ items: Array<EmailDomain>;
2009
+ }
2010
+ export interface AddEmailDomainV2Body {
2011
+ domain: string;
2012
+ }
2013
+ export interface AddEmailDomainV2Response {
2014
+ domain: EmailDomain;
2015
+ }
2016
+ export interface GetEmailDomainV2Response {
2017
+ domain: EmailDomain;
2018
+ }
2019
+ export interface VerifyEmailDomainV2Response {
2020
+ domain: EmailDomain;
2021
+ }
2022
+ export interface CancelCampaignV2Response {
2023
+ campaign: Broadcast;
2024
+ }
2025
+ export interface ListFunctionsV2Response {
2026
+ items: Array<ZavuFunction>;
2027
+ nextCursor: string | null;
2028
+ }
2029
+ export interface GetFunctionV2Response {
2030
+ function: ZavuFunction;
2031
+ }
2032
+ export interface UpdateFunctionV2Response {
2033
+ function: ZavuFunction;
2034
+ }
2035
+ /** Params for `messages.send`. */
2036
+ export interface MessagesSendParams extends SendMessageRequest {
2037
+ }
2038
+ /** Params for `messages.list`. */
2039
+ export interface MessagesListParams {
2040
+ status?: ListMessagesV2Status;
2041
+ to?: string;
2042
+ channel?: ChannelType;
2043
+ /** @defaultValue `50` */
2044
+ limit?: number;
2045
+ /** Opaque `nextCursor` from the previous page. */
2046
+ cursor?: string;
2047
+ }
2048
+ /** Params for `conversations.list`. */
2049
+ export interface ConversationsListParams {
2050
+ /** Only threads that have carried this transport. */
2051
+ channel?: ChannelType;
2052
+ /**
2053
+ * Keep only threads last handled from this address. Resolved like `from` on `POST
2054
+ * /v2/messages`, narrowed by `channel` when given.
2055
+ */
2056
+ from?: string;
2057
+ /** Identity search (number, email, username). Never message bodies. */
2058
+ search?: string;
2059
+ /** @defaultValue `50` */
2060
+ limit?: number;
2061
+ /** Opaque `nextCursor` from the previous page. */
2062
+ cursor?: string;
2063
+ }
2064
+ /** Params for `conversations.listMessages`. */
2065
+ export interface ConversationsListMessagesParams {
2066
+ /** @defaultValue `50` */
2067
+ limit?: number;
2068
+ /** Opaque `nextCursor` from the previous page. */
2069
+ cursor?: string;
2070
+ }
2071
+ /** Params for `contacts.list`. */
2072
+ export interface ContactsListParams {
2073
+ search?: string;
2074
+ tag?: Array<string>;
2075
+ /** @defaultValue `50` */
2076
+ limit?: number;
2077
+ /** Opaque `nextCursor` from the previous page. */
2078
+ cursor?: string;
2079
+ }
2080
+ /** Params for `contacts.create`. */
2081
+ export interface ContactsCreateParams extends ContactCreateRequest {
2082
+ }
2083
+ /** Params for `contacts.update`. */
2084
+ export interface ContactsUpdateParams extends ContactUpdateRequest {
2085
+ }
2086
+ /** Params for `channels.list`. */
2087
+ export interface ChannelsListParams {
2088
+ /** @defaultValue `50` */
2089
+ limit?: number;
2090
+ /** Opaque `nextCursor` from the previous page. */
2091
+ cursor?: string;
2092
+ }
2093
+ /** Params for `channels.connect`. */
2094
+ export type ChannelsConnectParams = ChannelConnectRequest;
2095
+ /** Params for `templates.list`. */
2096
+ export interface TemplatesListParams {
2097
+ /** @defaultValue `50` */
2098
+ limit?: number;
2099
+ /** Opaque `nextCursor` from the previous page. */
2100
+ cursor?: string;
2101
+ }
2102
+ /** Params for `templates.create`. */
2103
+ export interface TemplatesCreateParams extends TemplateCreateRequest {
2104
+ }
2105
+ /** Params for `templates.submit`. */
2106
+ export interface TemplatesSubmitParams extends TemplateSubmitRequest {
2107
+ }
2108
+ /** Params for `campaigns.list`. */
2109
+ export interface CampaignsListParams {
2110
+ status?: BroadcastStatus;
2111
+ /** @defaultValue `50` */
2112
+ limit?: number;
2113
+ /** Opaque, from a previous `nextCursor`. */
2114
+ cursor?: string;
2115
+ }
2116
+ /** Params for `campaigns.create`. */
2117
+ export interface CampaignsCreateParams extends BroadcastCreateRequest {
2118
+ }
2119
+ /** Params for `campaigns.send`. */
2120
+ export interface CampaignsSendParams extends BroadcastSendRequest {
2121
+ }
2122
+ /** Params for `campaigns.recipients.add`. */
2123
+ export interface CampaignsRecipientsAddParams extends BroadcastContactsAddRequest {
2124
+ }
2125
+ /** Params for `webhook.set`. */
2126
+ export interface WebhookSetParams extends ProjectWebhookV2Put {
2127
+ }
2128
+ /** Params for `agents.list`. */
2129
+ export interface AgentsListParams {
2130
+ /** @defaultValue `50` */
2131
+ limit?: number;
2132
+ /** Opaque `nextCursor` from the previous page. */
2133
+ cursor?: string;
2134
+ }
2135
+ /** Params for `agents.create`. */
2136
+ export interface AgentsCreateParams extends AgentCreateStandaloneRequest {
2137
+ }
2138
+ /** Params for `agents.update`. */
2139
+ export interface AgentsUpdateParams extends AgentUpdateRequest {
2140
+ }
2141
+ /** Params for `agents.test`. */
2142
+ export interface AgentsTestParams extends AgentTestRequest {
2143
+ }
2144
+ /** Params for `agents.channels.connect`. */
2145
+ export interface AgentsChannelsConnectParams extends ConnectAgentChannelV2Body {
2146
+ }
2147
+ /** Params for `numbers.searchAvailable`. */
2148
+ export interface NumbersSearchAvailableParams {
2149
+ countryCode: string;
2150
+ type?: PhoneNumberType;
2151
+ contains?: string;
2152
+ capabilities?: string;
2153
+ /** @defaultValue `10` */
2154
+ limit?: number;
2155
+ }
2156
+ /** Params for `numbers.purchase`. */
2157
+ export interface NumbersPurchaseParams extends PhoneNumberPurchaseRequest {
2158
+ }
2159
+ /** Params for `emailDomains.create`. */
2160
+ export interface EmailDomainsCreateParams extends AddEmailDomainV2Body {
2161
+ }
2162
+ /** Params for `functions.list`. */
2163
+ export interface FunctionsListParams {
2164
+ /** @defaultValue `50` */
2165
+ limit?: number;
2166
+ cursor?: string;
2167
+ }
2168
+ /** Params for `functions.update`. */
2169
+ export interface FunctionsUpdateParams extends FunctionUpdateRequest {
2170
+ }
2171
+ //# sourceMappingURL=types.d.mts.map