@wazapi/sdk 0.2.0 → 0.4.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.
- package/README.md +21 -0
- package/dist/client.d.ts +32 -2
- package/dist/client.js +60 -2
- package/dist/error.d.ts +7 -0
- package/dist/error.js +18 -0
- package/dist/types.d.ts +188 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,6 +108,27 @@ operation is created):
|
|
|
108
108
|
| `template_parameter_count_mismatch` | `parameters.length` ≠ `body_parameter_count`. |
|
|
109
109
|
| `template_format_unsupported` | Needs media/variable header, named params, buttons. |
|
|
110
110
|
|
|
111
|
+
Compliance gates on template sends (rejected synchronously with 403/422, and
|
|
112
|
+
re-checked by the worker — the same codes can appear as `error.code` on the
|
|
113
|
+
polled operation):
|
|
114
|
+
|
|
115
|
+
| Code | Meaning |
|
|
116
|
+
| --------------------------------------- | ------------------------------------------------------------------------ |
|
|
117
|
+
| `marketing_sends_disabled` | MARKETING sending is off for the company (an owner enables it in the dashboard) or platform-wide. |
|
|
118
|
+
| `recipient_opted_out` | The recipient opted out (reply keyword, native WhatsApp control, or manual suppression). Filter on `contact.marketing_opted_out`. |
|
|
119
|
+
| `duplicate_template_send` | Same template already sent to this phone in the last 24h. |
|
|
120
|
+
| `template_frequency_cap_exceeded` | Per-contact MARKETING cap (1/24h, 3/7 days). |
|
|
121
|
+
| `company_daily_marketing_cap_exceeded` | Company-wide daily MARKETING cap. |
|
|
122
|
+
| `channel_marketing_paused` | Meta flagged the number's quality; MARKETING is paused temporarily. |
|
|
123
|
+
| `template_quality_blocked` | This specific template dropped to RED quality on Meta. |
|
|
124
|
+
| `send_pacing_timeout` | Operation-only: delivery was deferred by per-channel pacing for too long. |
|
|
125
|
+
|
|
126
|
+
Delivery is paced per channel to protect number quality, so an accepted `202`
|
|
127
|
+
can take longer to complete under load — poll the operation instead of
|
|
128
|
+
re-sending. AUTHENTICATION (OTP) templates are exempt from opt-outs and caps.
|
|
129
|
+
Use `error.isComplianceBlocked` to branch on this whole family, and the
|
|
130
|
+
`SendComplianceErrorCode` type to narrow `operation.error.code`.
|
|
131
|
+
|
|
111
132
|
## Contacts
|
|
112
133
|
|
|
113
134
|
```ts
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AcceptedResult, Channel, Contact, ContactWrite, Conversation, ExecuteFlowInput, Flow, ListParams, Message, Operation, Paginated, SendMessageInput, Template } from './types.js';
|
|
1
|
+
import type { AcceptedResult, Channel, Contact, ContactWrite, Conversation, ConversationDetail, ExecuteFlowInput, Flow, ListParams, Message, Operation, Paginated, SendMessageInput, StoreBatchResult, StoreOrder, StoreOrderStatus, StoreProduct, StoreProductWrite, StoreSummary, Template } from './types.js';
|
|
2
2
|
export interface WazapiClientOptions {
|
|
3
3
|
/** Bearer token issued in Settings → Wazapi API (starts with `waz_api_`). */
|
|
4
4
|
token: string;
|
|
@@ -45,7 +45,15 @@ export declare class WazapiClient {
|
|
|
45
45
|
getFlow(uuid: string): Promise<Flow>;
|
|
46
46
|
executeFlow(flowUuid: string, input: ExecuteFlowInput, idempotencyKey?: string): Promise<AcceptedResult>;
|
|
47
47
|
listConversations(params?: ListParams): Promise<Paginated<Conversation>>;
|
|
48
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Everything about the chat in one call: contact (with tags), assigned agent
|
|
50
|
+
* and group, channel, status and counters. Pass `options.include = 'messages'`
|
|
51
|
+
* to embed the first page of messages — audio messages carry their
|
|
52
|
+
* `transcript` as a first-level field.
|
|
53
|
+
*/
|
|
54
|
+
getConversation(uuid: string, options?: {
|
|
55
|
+
include?: 'messages';
|
|
56
|
+
}): Promise<ConversationDetail>;
|
|
49
57
|
listMessages(conversationUuid: string, params?: ListParams): Promise<Paginated<Message>>;
|
|
50
58
|
sendMessage(input: SendMessageInput, idempotencyKey?: string): Promise<AcceptedResult>;
|
|
51
59
|
/** Convenience wrapper for a plain text send. */
|
|
@@ -56,6 +64,28 @@ export declare class WazapiClient {
|
|
|
56
64
|
language?: string;
|
|
57
65
|
parameters?: string[];
|
|
58
66
|
}, idempotencyKey?: string): Promise<AcceptedResult>;
|
|
67
|
+
/** Storefront status, public URL and product/order counts. Requires `store:read`. */
|
|
68
|
+
getStore(): Promise<StoreSummary>;
|
|
69
|
+
listStoreProducts(params?: ListParams): Promise<Paginated<StoreProduct>>;
|
|
70
|
+
getStoreProduct(uuid: string): Promise<StoreProduct>;
|
|
71
|
+
createStoreProduct(input: StoreProductWrite): Promise<StoreProduct>;
|
|
72
|
+
updateStoreProduct(uuid: string, input: StoreProductWrite): Promise<StoreProduct>;
|
|
73
|
+
/**
|
|
74
|
+
* Creates or updates up to 100 products in one call with a per-item result —
|
|
75
|
+
* one invalid product does not fail the batch. Items whose `import_handle`
|
|
76
|
+
* matches an existing product UPDATE it instead of creating a duplicate: this
|
|
77
|
+
* is the migration path for an external catalog (Shopify, an ERP).
|
|
78
|
+
*/
|
|
79
|
+
batchStoreProducts(products: StoreProductWrite[]): Promise<StoreBatchResult>;
|
|
80
|
+
listStoreOrders(params?: ListParams): Promise<Paginated<StoreOrder>>;
|
|
81
|
+
getStoreOrder(uuid: string): Promise<StoreOrder>;
|
|
82
|
+
/**
|
|
83
|
+
* Transitions an order through its state machine (novo→confirmado→pago→entregue,
|
|
84
|
+
* cancel from any non-terminal state). An invalid transition throws a
|
|
85
|
+
* `WazapiError` with code `invalid_status_transition` (422). Cancelling
|
|
86
|
+
* restores tracked stock.
|
|
87
|
+
*/
|
|
88
|
+
updateStoreOrderStatus(uuid: string, status: Exclude<StoreOrderStatus, 'novo'>): Promise<StoreOrder>;
|
|
59
89
|
getOperation(uuid: string): Promise<Operation>;
|
|
60
90
|
/**
|
|
61
91
|
* Polls an operation until it reaches a terminal status. Resolves with the final
|
package/dist/client.js
CHANGED
|
@@ -62,8 +62,17 @@ export class WazapiClient {
|
|
|
62
62
|
listConversations(params = {}) {
|
|
63
63
|
return this.request('GET', this.withQuery('/conversations', params));
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Everything about the chat in one call: contact (with tags), assigned agent
|
|
67
|
+
* and group, channel, status and counters. Pass `options.include = 'messages'`
|
|
68
|
+
* to embed the first page of messages — audio messages carry their
|
|
69
|
+
* `transcript` as a first-level field.
|
|
70
|
+
*/
|
|
71
|
+
async getConversation(uuid, options = {}) {
|
|
72
|
+
const path = options.include
|
|
73
|
+
? `/conversations/${encode(uuid)}?include=${options.include}`
|
|
74
|
+
: `/conversations/${encode(uuid)}`;
|
|
75
|
+
const body = await this.request('GET', path);
|
|
67
76
|
return body.data;
|
|
68
77
|
}
|
|
69
78
|
listMessages(conversationUuid, params = {}) {
|
|
@@ -81,6 +90,55 @@ export class WazapiClient {
|
|
|
81
90
|
sendTemplate(channelUuid, phone, template, idempotencyKey) {
|
|
82
91
|
return this.sendMessage({ channel_uuid: channelUuid, recipient: { phone }, type: 'template', content: template }, idempotencyKey);
|
|
83
92
|
}
|
|
93
|
+
// ---- Store ------------------------------------------------------------
|
|
94
|
+
/** Storefront status, public URL and product/order counts. Requires `store:read`. */
|
|
95
|
+
async getStore() {
|
|
96
|
+
const body = await this.request('GET', '/store');
|
|
97
|
+
return body.data;
|
|
98
|
+
}
|
|
99
|
+
listStoreProducts(params = {}) {
|
|
100
|
+
return this.request('GET', this.withQuery('/store/products', params));
|
|
101
|
+
}
|
|
102
|
+
async getStoreProduct(uuid) {
|
|
103
|
+
const body = await this.request('GET', `/store/products/${encode(uuid)}`);
|
|
104
|
+
return body.data;
|
|
105
|
+
}
|
|
106
|
+
async createStoreProduct(input) {
|
|
107
|
+
const body = await this.request('POST', '/store/products', {
|
|
108
|
+
body: input,
|
|
109
|
+
});
|
|
110
|
+
return body.data;
|
|
111
|
+
}
|
|
112
|
+
async updateStoreProduct(uuid, input) {
|
|
113
|
+
const body = await this.request('PATCH', `/store/products/${encode(uuid)}`, { body: input });
|
|
114
|
+
return body.data;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Creates or updates up to 100 products in one call with a per-item result —
|
|
118
|
+
* one invalid product does not fail the batch. Items whose `import_handle`
|
|
119
|
+
* matches an existing product UPDATE it instead of creating a duplicate: this
|
|
120
|
+
* is the migration path for an external catalog (Shopify, an ERP).
|
|
121
|
+
*/
|
|
122
|
+
batchStoreProducts(products) {
|
|
123
|
+
return this.request('POST', '/store/products/batch', { body: { products } });
|
|
124
|
+
}
|
|
125
|
+
listStoreOrders(params = {}) {
|
|
126
|
+
return this.request('GET', this.withQuery('/store/orders', params));
|
|
127
|
+
}
|
|
128
|
+
async getStoreOrder(uuid) {
|
|
129
|
+
const body = await this.request('GET', `/store/orders/${encode(uuid)}`);
|
|
130
|
+
return body.data;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Transitions an order through its state machine (novo→confirmado→pago→entregue,
|
|
134
|
+
* cancel from any non-terminal state). An invalid transition throws a
|
|
135
|
+
* `WazapiError` with code `invalid_status_transition` (422). Cancelling
|
|
136
|
+
* restores tracked stock.
|
|
137
|
+
*/
|
|
138
|
+
async updateStoreOrderStatus(uuid, status) {
|
|
139
|
+
const body = await this.request('POST', `/store/orders/${encode(uuid)}/status`, { body: { status } });
|
|
140
|
+
return body.data;
|
|
141
|
+
}
|
|
84
142
|
// ---- Operations -------------------------------------------------------
|
|
85
143
|
async getOperation(uuid) {
|
|
86
144
|
const body = await this.request('GET', `/operations/${encode(uuid)}`);
|
package/dist/error.d.ts
CHANGED
|
@@ -21,4 +21,11 @@ export declare class WazapiError extends Error {
|
|
|
21
21
|
});
|
|
22
22
|
/** True for 429 rate-limit responses. */
|
|
23
23
|
get isRateLimited(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* True when the send was refused by a compliance gate (opt-out, frequency
|
|
26
|
+
* cap, marketing policy, channel/template quality pause) rather than by a
|
|
27
|
+
* malformed request. Retrying without changing the audience will not help —
|
|
28
|
+
* fix the recipient list or the account policy instead.
|
|
29
|
+
*/
|
|
30
|
+
get isComplianceBlocked(): boolean;
|
|
24
31
|
}
|
package/dist/error.js
CHANGED
|
@@ -24,4 +24,22 @@ export class WazapiError extends Error {
|
|
|
24
24
|
get isRateLimited() {
|
|
25
25
|
return this.status === 429;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* True when the send was refused by a compliance gate (opt-out, frequency
|
|
29
|
+
* cap, marketing policy, channel/template quality pause) rather than by a
|
|
30
|
+
* malformed request. Retrying without changing the audience will not help —
|
|
31
|
+
* fix the recipient list or the account policy instead.
|
|
32
|
+
*/
|
|
33
|
+
get isComplianceBlocked() {
|
|
34
|
+
return [
|
|
35
|
+
'marketing_sends_disabled',
|
|
36
|
+
'template_sends_disabled',
|
|
37
|
+
'recipient_opted_out',
|
|
38
|
+
'duplicate_template_send',
|
|
39
|
+
'template_frequency_cap_exceeded',
|
|
40
|
+
'company_daily_marketing_cap_exceeded',
|
|
41
|
+
'channel_marketing_paused',
|
|
42
|
+
'template_quality_blocked',
|
|
43
|
+
].includes(this.code);
|
|
44
|
+
}
|
|
27
45
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type PublicApiScope = 'channels:read' | 'contacts:read' | 'contacts:write' | 'conversations:read' | 'messages:read' | 'messages:write' | 'templates:read' | 'flows:read' | 'flows:execute' | 'operations:read';
|
|
1
|
+
export type PublicApiScope = 'channels:read' | 'contacts:read' | 'contacts:write' | 'conversations:read' | 'messages:read' | 'messages:write' | 'templates:read' | 'flows:read' | 'flows:execute' | 'operations:read' | 'store:read' | 'store:write';
|
|
2
2
|
export interface PaginationMeta {
|
|
3
3
|
next_cursor: string | null;
|
|
4
4
|
}
|
|
@@ -30,6 +30,14 @@ export interface Contact {
|
|
|
30
30
|
email: string | null;
|
|
31
31
|
tags: string[];
|
|
32
32
|
custom_fields: Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* True when the contact opted out of marketing messages (reply keyword such
|
|
35
|
+
* as PARAR/STOP, the native WhatsApp control, or manual suppression).
|
|
36
|
+
* Sending a MARKETING template to an opted-out contact fails with
|
|
37
|
+
* `recipient_opted_out` — filter your audience on this before a campaign.
|
|
38
|
+
*/
|
|
39
|
+
marketing_opted_out: boolean;
|
|
40
|
+
marketing_opt_out_at: string | null;
|
|
33
41
|
last_interaction_at: string | null;
|
|
34
42
|
created_at: string | null;
|
|
35
43
|
updated_at: string | null;
|
|
@@ -80,17 +88,50 @@ export interface Conversation {
|
|
|
80
88
|
created_at: string | null;
|
|
81
89
|
updated_at: string | null;
|
|
82
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* `GET /conversations/{uuid}` — everything about the chat in one call: contact
|
|
93
|
+
* (with tags), assigned agent and group, channel, status and counters. Pass
|
|
94
|
+
* `include: 'messages'` to embed the first page of messages.
|
|
95
|
+
*/
|
|
96
|
+
export interface ConversationDetail extends Conversation {
|
|
97
|
+
channel_provider: string | null;
|
|
98
|
+
assigned_agent: {
|
|
99
|
+
uuid: string;
|
|
100
|
+
name: string | null;
|
|
101
|
+
} | null;
|
|
102
|
+
assigned_group: {
|
|
103
|
+
uuid: string;
|
|
104
|
+
name: string;
|
|
105
|
+
} | null;
|
|
106
|
+
message_count: number;
|
|
107
|
+
/** Present only when requested with `include: 'messages'`. */
|
|
108
|
+
messages?: Message[];
|
|
109
|
+
}
|
|
83
110
|
export interface Message {
|
|
84
111
|
uuid: string;
|
|
85
112
|
direction: 'inbound' | 'outbound';
|
|
86
113
|
type: string;
|
|
87
114
|
status: string;
|
|
88
115
|
content: Record<string, unknown>;
|
|
116
|
+
/**
|
|
117
|
+
* Transcription of an inbound audio message, when available. Populated
|
|
118
|
+
* asynchronously after transcription; also delivered via the
|
|
119
|
+
* `message.transcribed` webhook. `null` for non-audio messages and audios
|
|
120
|
+
* not yet transcribed.
|
|
121
|
+
*/
|
|
122
|
+
transcript: string | null;
|
|
89
123
|
provider_message_id: string | null;
|
|
90
124
|
created_at: string | null;
|
|
91
125
|
updated_at: string | null;
|
|
92
126
|
}
|
|
93
127
|
export type OperationStatus = 'queued' | 'processing' | 'waiting' | 'succeeded' | 'failed';
|
|
128
|
+
/**
|
|
129
|
+
* Compliance codes the send guard can answer with. They surface both as a
|
|
130
|
+
* synchronous 4xx on `POST /messages` (403 for the two `*_disabled` codes,
|
|
131
|
+
* 422 for the rest) and as `error.code` on the polled operation —
|
|
132
|
+
* `send_pacing_timeout` only ever appears on the operation.
|
|
133
|
+
*/
|
|
134
|
+
export type SendComplianceErrorCode = 'marketing_sends_disabled' | 'template_sends_disabled' | 'recipient_opted_out' | 'duplicate_template_send' | 'template_frequency_cap_exceeded' | 'company_daily_marketing_cap_exceeded' | 'channel_marketing_paused' | 'template_quality_blocked' | 'send_pacing_timeout';
|
|
94
135
|
export interface Operation {
|
|
95
136
|
uuid: string;
|
|
96
137
|
type: 'message.send' | 'flow.execute';
|
|
@@ -143,7 +184,132 @@ export interface AcceptedResult {
|
|
|
143
184
|
/** True when the request replayed a previously accepted idempotent operation. */
|
|
144
185
|
replayed: boolean;
|
|
145
186
|
}
|
|
146
|
-
export
|
|
187
|
+
export interface StoreSummary {
|
|
188
|
+
enabled: boolean;
|
|
189
|
+
mode: 'links_only' | 'store_only' | 'both' | null;
|
|
190
|
+
slug: string | null;
|
|
191
|
+
/** Public storefront path (relative, e.g. `/loja/minha-loja`). */
|
|
192
|
+
url: string | null;
|
|
193
|
+
product_count: number;
|
|
194
|
+
order_count: number;
|
|
195
|
+
}
|
|
196
|
+
export interface StoreProductVariant {
|
|
197
|
+
uuid: string;
|
|
198
|
+
label: string;
|
|
199
|
+
price_cents: number | null;
|
|
200
|
+
stock: number | null;
|
|
201
|
+
active: boolean;
|
|
202
|
+
position: number;
|
|
203
|
+
}
|
|
204
|
+
export interface StoreProduct {
|
|
205
|
+
uuid: string;
|
|
206
|
+
name: string;
|
|
207
|
+
description: string | null;
|
|
208
|
+
category_uuid: string | null;
|
|
209
|
+
price_cents: number;
|
|
210
|
+
promo_price_cents: number | null;
|
|
211
|
+
effective_price_cents: number;
|
|
212
|
+
images: string[];
|
|
213
|
+
highlighted: boolean;
|
|
214
|
+
track_stock: boolean;
|
|
215
|
+
stock: number | null;
|
|
216
|
+
active: boolean;
|
|
217
|
+
position: number;
|
|
218
|
+
/**
|
|
219
|
+
* External catalog handle (e.g. Shopify Handle). Products sharing the same
|
|
220
|
+
* handle are updated on re-import/batch instead of duplicated.
|
|
221
|
+
*/
|
|
222
|
+
import_handle: string | null;
|
|
223
|
+
variants: StoreProductVariant[];
|
|
224
|
+
created_at: string | null;
|
|
225
|
+
updated_at: string | null;
|
|
226
|
+
}
|
|
227
|
+
export interface StoreProductWrite {
|
|
228
|
+
name: string;
|
|
229
|
+
description?: string | null;
|
|
230
|
+
category_uuid?: string | null;
|
|
231
|
+
price_cents: number;
|
|
232
|
+
promo_price_cents?: number | null;
|
|
233
|
+
highlighted?: boolean;
|
|
234
|
+
track_stock?: boolean;
|
|
235
|
+
stock?: number | null;
|
|
236
|
+
active?: boolean;
|
|
237
|
+
position?: number;
|
|
238
|
+
import_handle?: string | null;
|
|
239
|
+
/**
|
|
240
|
+
* On update the variant list replaces the existing one: variants whose `uuid`
|
|
241
|
+
* is present are kept/updated, the rest are deleted.
|
|
242
|
+
*/
|
|
243
|
+
variants?: {
|
|
244
|
+
uuid?: string | null;
|
|
245
|
+
label: string;
|
|
246
|
+
price_cents?: number | null;
|
|
247
|
+
stock?: number | null;
|
|
248
|
+
active?: boolean;
|
|
249
|
+
}[];
|
|
250
|
+
}
|
|
251
|
+
export type StoreOrderStatus = 'novo' | 'confirmado' | 'pago' | 'entregue' | 'cancelado';
|
|
252
|
+
export interface StoreOrderItem {
|
|
253
|
+
product_uuid: string;
|
|
254
|
+
name: string;
|
|
255
|
+
variant_label: string | null;
|
|
256
|
+
quantity: number;
|
|
257
|
+
unit_price_cents: number;
|
|
258
|
+
total_cents: number;
|
|
259
|
+
}
|
|
260
|
+
export type StoreOrderSource = 'storefront' | 'whatsapp_catalog';
|
|
261
|
+
export interface StoreOrder {
|
|
262
|
+
uuid: string;
|
|
263
|
+
/** Short human reference (first 8 chars of the uuid) shown to the customer. */
|
|
264
|
+
ref: string;
|
|
265
|
+
status: StoreOrderStatus;
|
|
266
|
+
/** Where the order was placed: storefront checkout or the native WhatsApp catalog. */
|
|
267
|
+
source: StoreOrderSource;
|
|
268
|
+
/** Provider-side id for orders that originated outside the storefront (WhatsApp catalog order message id). */
|
|
269
|
+
provider_order_id: string | null;
|
|
270
|
+
/**
|
|
271
|
+
* Allowlisted attribution subset stamped at creation (utm_*, click IDs incl.
|
|
272
|
+
* ctwa_clid, ad referral fields). Conversation values win over contact values
|
|
273
|
+
* (last touch over first touch). Null when the order has no attributable source.
|
|
274
|
+
*/
|
|
275
|
+
tracking: Record<string, unknown> | null;
|
|
276
|
+
customer_name: string;
|
|
277
|
+
customer_phone: string;
|
|
278
|
+
contact_uuid: string | null;
|
|
279
|
+
/** Inbox conversation opened by the order automation, when available. */
|
|
280
|
+
conversation_uuid: string | null;
|
|
281
|
+
items: StoreOrderItem[];
|
|
282
|
+
subtotal_cents: number;
|
|
283
|
+
shipping_name: string | null;
|
|
284
|
+
shipping_cents: number;
|
|
285
|
+
total_cents: number;
|
|
286
|
+
/** `catalog` = order from the native WhatsApp catalog (payment arranged in chat). */
|
|
287
|
+
payment_method: 'pix' | 'link' | 'on_delivery' | 'catalog';
|
|
288
|
+
notes: string | null;
|
|
289
|
+
created_at: string | null;
|
|
290
|
+
updated_at: string | null;
|
|
291
|
+
}
|
|
292
|
+
export type StoreBatchResultItem = {
|
|
293
|
+
index: number;
|
|
294
|
+
status: 'created' | 'updated';
|
|
295
|
+
uuid: string;
|
|
296
|
+
} | {
|
|
297
|
+
index: number;
|
|
298
|
+
status: 'error';
|
|
299
|
+
error: {
|
|
300
|
+
code: string;
|
|
301
|
+
message: string;
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
export interface StoreBatchResult {
|
|
305
|
+
data: StoreBatchResultItem[];
|
|
306
|
+
meta: {
|
|
307
|
+
created: number;
|
|
308
|
+
updated: number;
|
|
309
|
+
failed: number;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
export type WebhookEventType = 'message.received' | 'message.status.updated' | 'conversation.created' | 'conversation.updated' | 'flow.execution.updated' | 'order.created' | 'webhook.test';
|
|
147
313
|
/**
|
|
148
314
|
* Allowlisted attribution subset of the contact's and conversation's custom
|
|
149
315
|
* fields. Conversation values win over contact values (last touch over first
|
|
@@ -200,6 +366,24 @@ export interface FlowExecutionUpdatedData {
|
|
|
200
366
|
message: string | null;
|
|
201
367
|
} | null;
|
|
202
368
|
}
|
|
369
|
+
/** A store order was created — storefront checkout or native WhatsApp catalog. */
|
|
370
|
+
export interface OrderCreatedData extends WebhookContactRefs {
|
|
371
|
+
order_uuid: string;
|
|
372
|
+
ref: string;
|
|
373
|
+
status: string;
|
|
374
|
+
source: StoreOrderSource;
|
|
375
|
+
customer_name: string;
|
|
376
|
+
customer_phone: string;
|
|
377
|
+
contact_uuid: string | null;
|
|
378
|
+
items: StoreOrderItem[];
|
|
379
|
+
subtotal_cents: number;
|
|
380
|
+
shipping_name: string | null;
|
|
381
|
+
shipping_cents: number;
|
|
382
|
+
total_cents: number;
|
|
383
|
+
payment_method: string;
|
|
384
|
+
notes: string | null;
|
|
385
|
+
created_at: string | null;
|
|
386
|
+
}
|
|
203
387
|
export interface WebhookTestData {
|
|
204
388
|
integration_uuid: string;
|
|
205
389
|
message: string;
|
|
@@ -217,7 +401,8 @@ export type MessageStatusUpdatedEvent = WebhookEnvelope<'message.status.updated'
|
|
|
217
401
|
export type ConversationCreatedEvent = WebhookEnvelope<'conversation.created', ConversationCreatedData>;
|
|
218
402
|
export type ConversationUpdatedEvent = WebhookEnvelope<'conversation.updated', ConversationUpdatedData>;
|
|
219
403
|
export type FlowExecutionUpdatedEvent = WebhookEnvelope<'flow.execution.updated', FlowExecutionUpdatedData>;
|
|
404
|
+
export type OrderCreatedEvent = WebhookEnvelope<'order.created', OrderCreatedData>;
|
|
220
405
|
export type WebhookTestEvent = WebhookEnvelope<'webhook.test', WebhookTestData>;
|
|
221
406
|
/** Discriminated on `type` — narrow it and `data` narrows with it. */
|
|
222
|
-
export type WazapiWebhookEvent = MessageReceivedEvent | MessageStatusUpdatedEvent | ConversationCreatedEvent | ConversationUpdatedEvent | FlowExecutionUpdatedEvent | WebhookTestEvent;
|
|
407
|
+
export type WazapiWebhookEvent = MessageReceivedEvent | MessageStatusUpdatedEvent | ConversationCreatedEvent | ConversationUpdatedEvent | FlowExecutionUpdatedEvent | OrderCreatedEvent | WebhookTestEvent;
|
|
223
408
|
export {};
|