@semboja/connect 0.1.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/LICENSE +21 -0
- package/README.md +304 -0
- package/dist/index.d.mts +739 -0
- package/dist/index.d.ts +739 -0
- package/dist/index.js +635 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +599 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +59 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
interface HttpClientOptions {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
timeout: number;
|
|
5
|
+
retries: number;
|
|
6
|
+
}
|
|
7
|
+
interface RequestOptions {
|
|
8
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
9
|
+
path: string;
|
|
10
|
+
body?: unknown;
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* HTTP client for making API requests
|
|
15
|
+
*/
|
|
16
|
+
declare class HttpClient {
|
|
17
|
+
private readonly baseUrl;
|
|
18
|
+
private readonly apiKey;
|
|
19
|
+
private readonly timeout;
|
|
20
|
+
private readonly retries;
|
|
21
|
+
constructor(options: HttpClientOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Make an HTTP request with retry logic
|
|
24
|
+
*/
|
|
25
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
26
|
+
/**
|
|
27
|
+
* Parse error response into appropriate error class
|
|
28
|
+
*/
|
|
29
|
+
private parseError;
|
|
30
|
+
/**
|
|
31
|
+
* GET request
|
|
32
|
+
*/
|
|
33
|
+
get<T>(path: string): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* POST request
|
|
36
|
+
*/
|
|
37
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Client configuration options
|
|
42
|
+
*/
|
|
43
|
+
interface ClientOptions {
|
|
44
|
+
/** API key (sk_live_* or sk_test_*) */
|
|
45
|
+
apiKey: string;
|
|
46
|
+
/** Base URL for the API (default: https://connect.semboja.tech) */
|
|
47
|
+
baseUrl?: string;
|
|
48
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
49
|
+
timeout?: number;
|
|
50
|
+
/** Number of retry attempts for failed requests (default: 3) */
|
|
51
|
+
retries?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Standard API response wrapper
|
|
55
|
+
*/
|
|
56
|
+
interface ApiResponse<T> {
|
|
57
|
+
success: boolean;
|
|
58
|
+
data: T;
|
|
59
|
+
meta: {
|
|
60
|
+
request_id: string;
|
|
61
|
+
latency_ms?: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* API error response
|
|
66
|
+
*/
|
|
67
|
+
interface ApiErrorResponse {
|
|
68
|
+
success: false;
|
|
69
|
+
error: {
|
|
70
|
+
code: string;
|
|
71
|
+
message: string;
|
|
72
|
+
};
|
|
73
|
+
meta: {
|
|
74
|
+
request_id: string;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
type MessageType = 'text' | 'template' | 'image' | 'video' | 'audio' | 'document' | 'interactive' | 'reaction';
|
|
78
|
+
interface SendMessageOptions {
|
|
79
|
+
/** Meta Phone Number ID */
|
|
80
|
+
phoneNumberId: string;
|
|
81
|
+
/** Recipient phone number with country code (e.g., +6281234567890) */
|
|
82
|
+
to: string;
|
|
83
|
+
}
|
|
84
|
+
interface SendTextOptions extends SendMessageOptions {
|
|
85
|
+
/** Message text content (max 4096 characters) */
|
|
86
|
+
text: string;
|
|
87
|
+
/** Enable URL preview in the message */
|
|
88
|
+
previewUrl?: boolean;
|
|
89
|
+
/** Message ID to reply to */
|
|
90
|
+
replyTo?: string;
|
|
91
|
+
}
|
|
92
|
+
interface TemplateLanguage {
|
|
93
|
+
code: string;
|
|
94
|
+
}
|
|
95
|
+
interface TemplateComponent {
|
|
96
|
+
type: 'header' | 'body' | 'button';
|
|
97
|
+
parameters?: TemplateParameter[];
|
|
98
|
+
sub_type?: string;
|
|
99
|
+
index?: number;
|
|
100
|
+
}
|
|
101
|
+
interface TemplateParameter {
|
|
102
|
+
type: 'text' | 'currency' | 'date_time' | 'image' | 'document' | 'video';
|
|
103
|
+
text?: string;
|
|
104
|
+
currency?: {
|
|
105
|
+
fallback_value: string;
|
|
106
|
+
code: string;
|
|
107
|
+
amount_1000: number;
|
|
108
|
+
};
|
|
109
|
+
date_time?: {
|
|
110
|
+
fallback_value: string;
|
|
111
|
+
};
|
|
112
|
+
image?: MediaObject;
|
|
113
|
+
document?: MediaObject;
|
|
114
|
+
video?: MediaObject;
|
|
115
|
+
}
|
|
116
|
+
interface Template {
|
|
117
|
+
name: string;
|
|
118
|
+
language: TemplateLanguage;
|
|
119
|
+
components?: TemplateComponent[];
|
|
120
|
+
}
|
|
121
|
+
interface SendTemplateOptions extends SendMessageOptions {
|
|
122
|
+
/** Template configuration */
|
|
123
|
+
template: Template;
|
|
124
|
+
}
|
|
125
|
+
interface MediaObject {
|
|
126
|
+
/** URL of the media file */
|
|
127
|
+
link?: string;
|
|
128
|
+
/** Media ID (if uploaded to WhatsApp) */
|
|
129
|
+
id?: string;
|
|
130
|
+
/** Caption for the media */
|
|
131
|
+
caption?: string;
|
|
132
|
+
/** Filename (for documents) */
|
|
133
|
+
filename?: string;
|
|
134
|
+
}
|
|
135
|
+
interface SendImageOptions extends SendMessageOptions {
|
|
136
|
+
/** Image configuration */
|
|
137
|
+
image: MediaObject;
|
|
138
|
+
/** Message ID to reply to */
|
|
139
|
+
replyTo?: string;
|
|
140
|
+
}
|
|
141
|
+
interface SendVideoOptions extends SendMessageOptions {
|
|
142
|
+
/** Video configuration */
|
|
143
|
+
video: MediaObject;
|
|
144
|
+
/** Message ID to reply to */
|
|
145
|
+
replyTo?: string;
|
|
146
|
+
}
|
|
147
|
+
interface SendAudioOptions extends SendMessageOptions {
|
|
148
|
+
/** Audio configuration */
|
|
149
|
+
audio: MediaObject;
|
|
150
|
+
/** Message ID to reply to */
|
|
151
|
+
replyTo?: string;
|
|
152
|
+
}
|
|
153
|
+
interface SendDocumentOptions extends SendMessageOptions {
|
|
154
|
+
/** Document configuration */
|
|
155
|
+
document: MediaObject;
|
|
156
|
+
/** Message ID to reply to */
|
|
157
|
+
replyTo?: string;
|
|
158
|
+
}
|
|
159
|
+
interface SendReactionOptions extends SendMessageOptions {
|
|
160
|
+
/** Reaction configuration */
|
|
161
|
+
reaction: {
|
|
162
|
+
/** Message ID to react to */
|
|
163
|
+
messageId: string;
|
|
164
|
+
/** Emoji to react with (empty string to remove reaction) */
|
|
165
|
+
emoji: string;
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
interface InteractiveButton {
|
|
169
|
+
type: 'reply';
|
|
170
|
+
reply: {
|
|
171
|
+
id: string;
|
|
172
|
+
title: string;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
interface InteractiveListSection {
|
|
176
|
+
title?: string;
|
|
177
|
+
rows: Array<{
|
|
178
|
+
id: string;
|
|
179
|
+
title: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
}>;
|
|
182
|
+
}
|
|
183
|
+
interface InteractiveMessage {
|
|
184
|
+
type: 'button' | 'list' | 'product' | 'product_list';
|
|
185
|
+
header?: {
|
|
186
|
+
type: 'text' | 'image' | 'video' | 'document';
|
|
187
|
+
text?: string;
|
|
188
|
+
image?: MediaObject;
|
|
189
|
+
video?: MediaObject;
|
|
190
|
+
document?: MediaObject;
|
|
191
|
+
};
|
|
192
|
+
body: {
|
|
193
|
+
text: string;
|
|
194
|
+
};
|
|
195
|
+
footer?: {
|
|
196
|
+
text: string;
|
|
197
|
+
};
|
|
198
|
+
action: {
|
|
199
|
+
button?: string;
|
|
200
|
+
buttons?: InteractiveButton[];
|
|
201
|
+
sections?: InteractiveListSection[];
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
interface SendInteractiveOptions extends SendMessageOptions {
|
|
205
|
+
/** Interactive message configuration */
|
|
206
|
+
interactive: InteractiveMessage;
|
|
207
|
+
/** Message ID to reply to */
|
|
208
|
+
replyTo?: string;
|
|
209
|
+
}
|
|
210
|
+
interface MessageContact {
|
|
211
|
+
input: string;
|
|
212
|
+
wa_id: string;
|
|
213
|
+
}
|
|
214
|
+
interface MessageResult {
|
|
215
|
+
id: string;
|
|
216
|
+
}
|
|
217
|
+
interface MessageResponseData {
|
|
218
|
+
messaging_product: 'whatsapp';
|
|
219
|
+
contacts: MessageContact[];
|
|
220
|
+
messages: MessageResult[];
|
|
221
|
+
}
|
|
222
|
+
type TemplateStatus = 'APPROVED' | 'PENDING' | 'REJECTED';
|
|
223
|
+
interface TemplateInfo {
|
|
224
|
+
name: string;
|
|
225
|
+
status: TemplateStatus;
|
|
226
|
+
category: string;
|
|
227
|
+
language: string;
|
|
228
|
+
}
|
|
229
|
+
interface ListTemplatesOptions {
|
|
230
|
+
/** Filter by status */
|
|
231
|
+
status?: TemplateStatus;
|
|
232
|
+
}
|
|
233
|
+
interface PhoneNumber {
|
|
234
|
+
id: string;
|
|
235
|
+
display_phone_number: string;
|
|
236
|
+
verified_name: string;
|
|
237
|
+
quality_rating?: string;
|
|
238
|
+
}
|
|
239
|
+
interface UsagePeriod {
|
|
240
|
+
start: string;
|
|
241
|
+
end: string;
|
|
242
|
+
}
|
|
243
|
+
interface UsageMessages {
|
|
244
|
+
sent: number;
|
|
245
|
+
received: number;
|
|
246
|
+
}
|
|
247
|
+
interface UsageData {
|
|
248
|
+
period: UsagePeriod;
|
|
249
|
+
messages: UsageMessages;
|
|
250
|
+
api_calls: number;
|
|
251
|
+
}
|
|
252
|
+
interface TriggerWebhookOptions {
|
|
253
|
+
/** Phone Number ID */
|
|
254
|
+
phoneNumberId: string;
|
|
255
|
+
/** Type of incoming message to simulate */
|
|
256
|
+
type?: 'text' | 'image';
|
|
257
|
+
/** Sender phone number */
|
|
258
|
+
from?: string;
|
|
259
|
+
/** Text content (for text type) */
|
|
260
|
+
text?: string;
|
|
261
|
+
}
|
|
262
|
+
interface VerifyWebhookOptions {
|
|
263
|
+
/** Raw request body (string or object) */
|
|
264
|
+
payload: string | object;
|
|
265
|
+
/** X-Semboja-Signature header value */
|
|
266
|
+
signature: string;
|
|
267
|
+
/** X-Semboja-Timestamp header value */
|
|
268
|
+
timestamp: string;
|
|
269
|
+
/** Your webhook secret */
|
|
270
|
+
secret: string;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Messages API resource
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* await client.messages.sendText({
|
|
279
|
+
* phoneNumberId: '123456789',
|
|
280
|
+
* to: '+6281234567890',
|
|
281
|
+
* text: 'Hello from Semboja!',
|
|
282
|
+
* });
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
declare class Messages {
|
|
286
|
+
private readonly http;
|
|
287
|
+
constructor(http: HttpClient);
|
|
288
|
+
/**
|
|
289
|
+
* Send a text message
|
|
290
|
+
*
|
|
291
|
+
* @param options - Text message options
|
|
292
|
+
* @returns Message response with message ID
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const result = await client.messages.sendText({
|
|
297
|
+
* phoneNumberId: '123456789',
|
|
298
|
+
* to: '+6281234567890',
|
|
299
|
+
* text: 'Hello, World!',
|
|
300
|
+
* previewUrl: true,
|
|
301
|
+
* });
|
|
302
|
+
* console.log('Message ID:', result.data.messages[0].id);
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
sendText(options: SendTextOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
306
|
+
/**
|
|
307
|
+
* Send a template message
|
|
308
|
+
*
|
|
309
|
+
* @param options - Template message options
|
|
310
|
+
* @returns Message response with message ID
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* const result = await client.messages.sendTemplate({
|
|
315
|
+
* phoneNumberId: '123456789',
|
|
316
|
+
* to: '+6281234567890',
|
|
317
|
+
* template: {
|
|
318
|
+
* name: 'hello_world',
|
|
319
|
+
* language: { code: 'en' },
|
|
320
|
+
* },
|
|
321
|
+
* });
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
sendTemplate(options: SendTemplateOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
325
|
+
/**
|
|
326
|
+
* Send an image message
|
|
327
|
+
*
|
|
328
|
+
* @param options - Image message options
|
|
329
|
+
* @returns Message response with message ID
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```typescript
|
|
333
|
+
* const result = await client.messages.sendImage({
|
|
334
|
+
* phoneNumberId: '123456789',
|
|
335
|
+
* to: '+6281234567890',
|
|
336
|
+
* image: {
|
|
337
|
+
* link: 'https://example.com/image.jpg',
|
|
338
|
+
* caption: 'Check this out!',
|
|
339
|
+
* },
|
|
340
|
+
* });
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
sendImage(options: SendImageOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
344
|
+
/**
|
|
345
|
+
* Send a video message
|
|
346
|
+
*
|
|
347
|
+
* @param options - Video message options
|
|
348
|
+
* @returns Message response with message ID
|
|
349
|
+
*/
|
|
350
|
+
sendVideo(options: SendVideoOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
351
|
+
/**
|
|
352
|
+
* Send an audio message
|
|
353
|
+
*
|
|
354
|
+
* @param options - Audio message options
|
|
355
|
+
* @returns Message response with message ID
|
|
356
|
+
*/
|
|
357
|
+
sendAudio(options: SendAudioOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
358
|
+
/**
|
|
359
|
+
* Send a document message
|
|
360
|
+
*
|
|
361
|
+
* @param options - Document message options
|
|
362
|
+
* @returns Message response with message ID
|
|
363
|
+
*
|
|
364
|
+
* @example
|
|
365
|
+
* ```typescript
|
|
366
|
+
* const result = await client.messages.sendDocument({
|
|
367
|
+
* phoneNumberId: '123456789',
|
|
368
|
+
* to: '+6281234567890',
|
|
369
|
+
* document: {
|
|
370
|
+
* link: 'https://example.com/invoice.pdf',
|
|
371
|
+
* filename: 'invoice.pdf',
|
|
372
|
+
* caption: 'Your invoice',
|
|
373
|
+
* },
|
|
374
|
+
* });
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
sendDocument(options: SendDocumentOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
378
|
+
/**
|
|
379
|
+
* Send a reaction to a message
|
|
380
|
+
*
|
|
381
|
+
* @param options - Reaction options
|
|
382
|
+
* @returns Message response
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```typescript
|
|
386
|
+
* // Add reaction
|
|
387
|
+
* await client.messages.sendReaction({
|
|
388
|
+
* phoneNumberId: '123456789',
|
|
389
|
+
* to: '+6281234567890',
|
|
390
|
+
* reaction: {
|
|
391
|
+
* messageId: 'wamid.xxx',
|
|
392
|
+
* emoji: '👍',
|
|
393
|
+
* },
|
|
394
|
+
* });
|
|
395
|
+
*
|
|
396
|
+
* // Remove reaction
|
|
397
|
+
* await client.messages.sendReaction({
|
|
398
|
+
* phoneNumberId: '123456789',
|
|
399
|
+
* to: '+6281234567890',
|
|
400
|
+
* reaction: {
|
|
401
|
+
* messageId: 'wamid.xxx',
|
|
402
|
+
* emoji: '',
|
|
403
|
+
* },
|
|
404
|
+
* });
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
sendReaction(options: SendReactionOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
408
|
+
/**
|
|
409
|
+
* Send an interactive message (buttons, lists, etc.)
|
|
410
|
+
*
|
|
411
|
+
* @param options - Interactive message options
|
|
412
|
+
* @returns Message response with message ID
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```typescript
|
|
416
|
+
* // Button message
|
|
417
|
+
* await client.messages.sendInteractive({
|
|
418
|
+
* phoneNumberId: '123456789',
|
|
419
|
+
* to: '+6281234567890',
|
|
420
|
+
* interactive: {
|
|
421
|
+
* type: 'button',
|
|
422
|
+
* body: { text: 'Choose an option:' },
|
|
423
|
+
* action: {
|
|
424
|
+
* buttons: [
|
|
425
|
+
* { type: 'reply', reply: { id: 'yes', title: 'Yes' } },
|
|
426
|
+
* { type: 'reply', reply: { id: 'no', title: 'No' } },
|
|
427
|
+
* ],
|
|
428
|
+
* },
|
|
429
|
+
* },
|
|
430
|
+
* });
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
sendInteractive(options: SendInteractiveOptions): Promise<ApiResponse<MessageResponseData>>;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Templates API resource
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```typescript
|
|
441
|
+
* const templates = await client.templates.list();
|
|
442
|
+
* const approved = await client.templates.list({ status: 'APPROVED' });
|
|
443
|
+
* ```
|
|
444
|
+
*/
|
|
445
|
+
declare class Templates {
|
|
446
|
+
private readonly http;
|
|
447
|
+
constructor(http: HttpClient);
|
|
448
|
+
/**
|
|
449
|
+
* List all message templates
|
|
450
|
+
*
|
|
451
|
+
* @param options - Optional filters
|
|
452
|
+
* @returns List of templates
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```typescript
|
|
456
|
+
* const templates = await client.templates.list();
|
|
457
|
+
* console.log('Templates:', templates.data);
|
|
458
|
+
*
|
|
459
|
+
* // Filter by status
|
|
460
|
+
* const approved = await client.templates.list({ status: 'APPROVED' });
|
|
461
|
+
* ```
|
|
462
|
+
*/
|
|
463
|
+
list(options?: ListTemplatesOptions): Promise<ApiResponse<TemplateInfo[]>>;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Phone Numbers API resource
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* ```typescript
|
|
471
|
+
* const phoneNumbers = await client.phoneNumbers.list();
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
declare class PhoneNumbers {
|
|
475
|
+
private readonly http;
|
|
476
|
+
constructor(http: HttpClient);
|
|
477
|
+
/**
|
|
478
|
+
* List all phone numbers configured for your account
|
|
479
|
+
*
|
|
480
|
+
* @returns List of phone numbers
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* ```typescript
|
|
484
|
+
* const phoneNumbers = await client.phoneNumbers.list();
|
|
485
|
+
* for (const phone of phoneNumbers.data) {
|
|
486
|
+
* console.log(`${phone.verified_name}: ${phone.display_phone_number}`);
|
|
487
|
+
* }
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
list(): Promise<ApiResponse<PhoneNumber[]>>;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Usage API resource
|
|
495
|
+
*
|
|
496
|
+
* @example
|
|
497
|
+
* ```typescript
|
|
498
|
+
* const usage = await client.usage.get();
|
|
499
|
+
* console.log(`Sent: ${usage.data.messages.sent}`);
|
|
500
|
+
* ```
|
|
501
|
+
*/
|
|
502
|
+
declare class Usage {
|
|
503
|
+
private readonly http;
|
|
504
|
+
constructor(http: HttpClient);
|
|
505
|
+
/**
|
|
506
|
+
* Get current usage statistics for the billing period
|
|
507
|
+
*
|
|
508
|
+
* @returns Usage statistics
|
|
509
|
+
*
|
|
510
|
+
* @example
|
|
511
|
+
* ```typescript
|
|
512
|
+
* const usage = await client.usage.get();
|
|
513
|
+
* console.log(`Period: ${usage.data.period.start} - ${usage.data.period.end}`);
|
|
514
|
+
* console.log(`Messages sent: ${usage.data.messages.sent}`);
|
|
515
|
+
* console.log(`Messages received: ${usage.data.messages.received}`);
|
|
516
|
+
* console.log(`API calls: ${usage.data.api_calls}`);
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
get(): Promise<ApiResponse<UsageData>>;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Test API resource (only works with sk_test_* keys)
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```typescript
|
|
527
|
+
* // Trigger a test webhook
|
|
528
|
+
* await client.test.triggerWebhook({
|
|
529
|
+
* phoneNumberId: '123456789',
|
|
530
|
+
* type: 'text',
|
|
531
|
+
* from: '+6281234567890',
|
|
532
|
+
* text: 'Test message',
|
|
533
|
+
* });
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
declare class Test {
|
|
537
|
+
private readonly http;
|
|
538
|
+
constructor(http: HttpClient);
|
|
539
|
+
/**
|
|
540
|
+
* Trigger a test webhook to simulate an incoming message
|
|
541
|
+
*
|
|
542
|
+
* **Note:** This only works with test API keys (sk_test_*)
|
|
543
|
+
*
|
|
544
|
+
* @param options - Webhook trigger options
|
|
545
|
+
* @returns Success response
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* await client.test.triggerWebhook({
|
|
550
|
+
* phoneNumberId: '123456789',
|
|
551
|
+
* type: 'text',
|
|
552
|
+
* from: '+6281234567890',
|
|
553
|
+
* text: 'Hello, this is a test incoming message!',
|
|
554
|
+
* });
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
triggerWebhook(options: TriggerWebhookOptions): Promise<ApiResponse<{
|
|
558
|
+
queued: boolean;
|
|
559
|
+
}>>;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Semboja WhatsApp API Client
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```typescript
|
|
567
|
+
* import { SembojaClient } from '@semboja/connect';
|
|
568
|
+
*
|
|
569
|
+
* // Simple initialization
|
|
570
|
+
* const client = new SembojaClient('sk_live_your_api_key');
|
|
571
|
+
*
|
|
572
|
+
* // With options
|
|
573
|
+
* const client = new SembojaClient({
|
|
574
|
+
* apiKey: process.env.SEMBOJA_API_KEY!,
|
|
575
|
+
* timeout: 60000,
|
|
576
|
+
* retries: 5,
|
|
577
|
+
* });
|
|
578
|
+
*
|
|
579
|
+
* // Send a message
|
|
580
|
+
* await client.messages.sendText({
|
|
581
|
+
* phoneNumberId: '123456789',
|
|
582
|
+
* to: '+6281234567890',
|
|
583
|
+
* text: 'Hello from Semboja!',
|
|
584
|
+
* });
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
declare class SembojaClient {
|
|
588
|
+
/** Messages API */
|
|
589
|
+
readonly messages: Messages;
|
|
590
|
+
/** Templates API */
|
|
591
|
+
readonly templates: Templates;
|
|
592
|
+
/** Phone Numbers API */
|
|
593
|
+
readonly phoneNumbers: PhoneNumbers;
|
|
594
|
+
/** Usage API */
|
|
595
|
+
readonly usage: Usage;
|
|
596
|
+
/** Test API (only works with sk_test_* keys) */
|
|
597
|
+
readonly test: Test;
|
|
598
|
+
/** Whether the client is in test mode */
|
|
599
|
+
readonly isTestMode: boolean;
|
|
600
|
+
private readonly http;
|
|
601
|
+
/**
|
|
602
|
+
* Create a new Semboja client
|
|
603
|
+
*
|
|
604
|
+
* @param optionsOrApiKey - API key string or client options object
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* ```typescript
|
|
608
|
+
* // Using API key directly
|
|
609
|
+
* const client = new SembojaClient('sk_live_xxx');
|
|
610
|
+
*
|
|
611
|
+
* // Using options object
|
|
612
|
+
* const client = new SembojaClient({
|
|
613
|
+
* apiKey: 'sk_live_xxx',
|
|
614
|
+
* timeout: 60000,
|
|
615
|
+
* retries: 5,
|
|
616
|
+
* });
|
|
617
|
+
* ```
|
|
618
|
+
*/
|
|
619
|
+
constructor(optionsOrApiKey: string | ClientOptions);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Verify a webhook signature from Semboja
|
|
624
|
+
*
|
|
625
|
+
* @param options - Verification options
|
|
626
|
+
* @returns true if the signature is valid, false otherwise
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* ```typescript
|
|
630
|
+
* import { verifyWebhookSignature } from '@semboja/connect';
|
|
631
|
+
*
|
|
632
|
+
* // Express.js example
|
|
633
|
+
* app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
|
|
634
|
+
* const isValid = verifyWebhookSignature({
|
|
635
|
+
* payload: req.body,
|
|
636
|
+
* signature: req.headers['x-semboja-signature'] as string,
|
|
637
|
+
* timestamp: req.headers['x-semboja-timestamp'] as string,
|
|
638
|
+
* secret: process.env.WEBHOOK_SECRET!,
|
|
639
|
+
* });
|
|
640
|
+
*
|
|
641
|
+
* if (!isValid) {
|
|
642
|
+
* return res.status(401).send('Invalid signature');
|
|
643
|
+
* }
|
|
644
|
+
*
|
|
645
|
+
* // Process the webhook
|
|
646
|
+
* const event = JSON.parse(req.body.toString());
|
|
647
|
+
* console.log('Received event:', event);
|
|
648
|
+
*
|
|
649
|
+
* res.status(200).send('OK');
|
|
650
|
+
* });
|
|
651
|
+
* ```
|
|
652
|
+
*
|
|
653
|
+
* @example
|
|
654
|
+
* ```typescript
|
|
655
|
+
* // Hono example
|
|
656
|
+
* app.post('/webhook', async (c) => {
|
|
657
|
+
* const body = await c.req.text();
|
|
658
|
+
* const signature = c.req.header('x-semboja-signature');
|
|
659
|
+
* const timestamp = c.req.header('x-semboja-timestamp');
|
|
660
|
+
*
|
|
661
|
+
* const isValid = verifyWebhookSignature({
|
|
662
|
+
* payload: body,
|
|
663
|
+
* signature: signature!,
|
|
664
|
+
* timestamp: timestamp!,
|
|
665
|
+
* secret: process.env.WEBHOOK_SECRET!,
|
|
666
|
+
* });
|
|
667
|
+
*
|
|
668
|
+
* if (!isValid) {
|
|
669
|
+
* return c.text('Invalid signature', 401);
|
|
670
|
+
* }
|
|
671
|
+
*
|
|
672
|
+
* const event = JSON.parse(body);
|
|
673
|
+
* // Process the webhook...
|
|
674
|
+
*
|
|
675
|
+
* return c.text('OK');
|
|
676
|
+
* });
|
|
677
|
+
* ```
|
|
678
|
+
*/
|
|
679
|
+
declare function verifyWebhookSignature(options: VerifyWebhookOptions): boolean;
|
|
680
|
+
/**
|
|
681
|
+
* Parse a webhook payload into a typed event object
|
|
682
|
+
*
|
|
683
|
+
* @param payload - Raw webhook payload (string or object)
|
|
684
|
+
* @returns Parsed webhook event
|
|
685
|
+
*/
|
|
686
|
+
declare function parseWebhookPayload<T = unknown>(payload: string | object): T;
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Base error class for all Semboja API errors
|
|
690
|
+
*/
|
|
691
|
+
declare class SembojaError extends Error {
|
|
692
|
+
/** Error code from the API */
|
|
693
|
+
readonly code: string;
|
|
694
|
+
/** HTTP status code */
|
|
695
|
+
readonly statusCode: number;
|
|
696
|
+
/** Request ID for debugging */
|
|
697
|
+
readonly requestId?: string;
|
|
698
|
+
constructor(message: string, code: string, statusCode: number, requestId?: string);
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Authentication error (invalid or missing API key)
|
|
702
|
+
*/
|
|
703
|
+
declare class AuthenticationError extends SembojaError {
|
|
704
|
+
constructor(message: string, requestId?: string);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Rate limit exceeded error
|
|
708
|
+
*/
|
|
709
|
+
declare class RateLimitError extends SembojaError {
|
|
710
|
+
/** When the rate limit resets (Unix timestamp) */
|
|
711
|
+
readonly resetAt?: number;
|
|
712
|
+
constructor(message: string, requestId?: string, resetAt?: number);
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Validation error (invalid request parameters)
|
|
716
|
+
*/
|
|
717
|
+
declare class ValidationError extends SembojaError {
|
|
718
|
+
constructor(message: string, requestId?: string);
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Resource not found error
|
|
722
|
+
*/
|
|
723
|
+
declare class NotFoundError extends SembojaError {
|
|
724
|
+
constructor(message: string, code: string, requestId?: string);
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Server error from Semboja API
|
|
728
|
+
*/
|
|
729
|
+
declare class ServerError extends SembojaError {
|
|
730
|
+
constructor(message: string, requestId?: string);
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Network or connection error
|
|
734
|
+
*/
|
|
735
|
+
declare class NetworkError extends SembojaError {
|
|
736
|
+
constructor(message: string);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
export { type ApiErrorResponse, type ApiResponse, AuthenticationError, type ClientOptions, type InteractiveButton, type InteractiveListSection, type InteractiveMessage, type ListTemplatesOptions, type MediaObject, type MessageContact, type MessageResponseData, type MessageResult, type MessageType, NetworkError, NotFoundError, type PhoneNumber, RateLimitError, SembojaClient, SembojaError, type SendAudioOptions, type SendDocumentOptions, type SendImageOptions, type SendInteractiveOptions, type SendMessageOptions, type SendReactionOptions, type SendTemplateOptions, type SendTextOptions, type SendVideoOptions, ServerError, type Template, type TemplateComponent, type TemplateInfo, type TemplateLanguage, type TemplateParameter, type TemplateStatus, type TriggerWebhookOptions, type UsageData, type UsageMessages, type UsagePeriod, ValidationError, type VerifyWebhookOptions, parseWebhookPayload, verifyWebhookSignature };
|