waba-toolkit 0.1.3 → 0.3.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.
@@ -0,0 +1,759 @@
1
+ interface WABAClientOptions {
2
+ /** Meta access token with whatsapp_business_messaging permission */
3
+ accessToken: string;
4
+ /** Meta App Secret for webhook signature verification */
5
+ appSecret?: string;
6
+ /** API version (default: 'v22.0') */
7
+ apiVersion?: string;
8
+ /** Base URL (default: 'https://graph.facebook.com') */
9
+ baseUrl?: string;
10
+ }
11
+ interface GetMediaOptions {
12
+ /** Return ArrayBuffer instead of ReadableStream (default: false) */
13
+ asBuffer?: boolean;
14
+ }
15
+
16
+ /**
17
+ * Media metadata returned from WABA API.
18
+ * Field names are normalized from snake_case to camelCase.
19
+ */
20
+ interface MediaMetadata {
21
+ id: string;
22
+ /** Normalized from mime_type */
23
+ mimeType: string;
24
+ sha256: string;
25
+ /** Normalized from file_size (string → number) */
26
+ fileSize: number;
27
+ /** Temporary URL (expires in 5 minutes) */
28
+ url: string;
29
+ }
30
+ interface MediaStreamResult extends MediaMetadata {
31
+ stream: ReadableStream<Uint8Array>;
32
+ }
33
+ interface MediaBufferResult extends MediaMetadata {
34
+ buffer: ArrayBuffer;
35
+ }
36
+
37
+ /**
38
+ * Client for WhatsApp Business API media operations.
39
+ */
40
+ declare class WABAClient {
41
+ private readonly accessToken;
42
+ private readonly appSecret?;
43
+ private readonly apiVersion;
44
+ private readonly baseUrl;
45
+ constructor(options: WABAClientOptions);
46
+ /**
47
+ * Verifies webhook signature using HMAC-SHA256.
48
+ * Requires appSecret to be set in constructor options.
49
+ *
50
+ * @throws {WABASignatureError} If appSecret was not provided in constructor
51
+ * @returns true if signature is valid, false otherwise
52
+ */
53
+ verifyWebhook(signature: string | undefined, rawBody: Buffer | string): boolean;
54
+ /**
55
+ * Fetches media by ID from WhatsApp Business API.
56
+ *
57
+ * Step 1: GET /{apiVersion}/{mediaId} → retrieves temporary URL + metadata
58
+ * Step 2: GET {temporaryUrl} → downloads binary content
59
+ *
60
+ * @throws {WABAMediaError} - Media not found (404) or access denied
61
+ * @throws {WABANetworkError} - Network/connection failures
62
+ */
63
+ getMedia(mediaId: string): Promise<MediaStreamResult>;
64
+ getMedia(mediaId: string, options: {
65
+ asBuffer: true;
66
+ }): Promise<MediaBufferResult>;
67
+ getMedia(mediaId: string, options?: GetMediaOptions): Promise<MediaStreamResult | MediaBufferResult>;
68
+ private fetchMediaMetadata;
69
+ private downloadMedia;
70
+ }
71
+
72
+ /**
73
+ * Types for WhatsApp Cloud API outbound messaging
74
+ */
75
+ interface TemplateParameter {
76
+ type: 'text' | 'currency' | 'date_time' | 'image' | 'document' | 'video';
77
+ text?: string;
78
+ currency?: {
79
+ fallback_value: string;
80
+ code: string;
81
+ amount_1000: number;
82
+ };
83
+ date_time?: {
84
+ fallback_value: string;
85
+ };
86
+ image?: {
87
+ link?: string;
88
+ id?: string;
89
+ };
90
+ document?: {
91
+ link?: string;
92
+ id?: string;
93
+ filename?: string;
94
+ };
95
+ video?: {
96
+ link?: string;
97
+ id?: string;
98
+ };
99
+ }
100
+ interface TemplateComponent {
101
+ type: 'header' | 'body' | 'button';
102
+ parameters?: TemplateParameter[];
103
+ sub_type?: 'quick_reply' | 'url';
104
+ index?: number;
105
+ }
106
+ interface SendTextMessageRequest {
107
+ messaging_product: 'whatsapp';
108
+ to: string;
109
+ type: 'text';
110
+ text: {
111
+ body: string;
112
+ preview_url?: boolean;
113
+ };
114
+ context?: {
115
+ message_id: string;
116
+ };
117
+ }
118
+ interface SendTemplateMessageRequest {
119
+ messaging_product: 'whatsapp';
120
+ to: string;
121
+ type: 'template';
122
+ template: {
123
+ name: string;
124
+ language: {
125
+ code: string;
126
+ policy?: 'deterministic';
127
+ };
128
+ components?: TemplateComponent[];
129
+ };
130
+ }
131
+ type MessagePayload = SendTextMessageRequest | SendTemplateMessageRequest | Record<string, unknown>;
132
+ interface SendMessageResponse {
133
+ messaging_product: 'whatsapp';
134
+ contacts: Array<{
135
+ input: string;
136
+ wa_id: string;
137
+ }>;
138
+ messages: Array<{
139
+ id: string;
140
+ }>;
141
+ }
142
+ interface SuccessResponse {
143
+ success: true;
144
+ }
145
+ interface RegisterPhoneRequest {
146
+ messaging_product: 'whatsapp';
147
+ pin: string;
148
+ }
149
+ interface DeregisterPhoneRequest {
150
+ messaging_product: 'whatsapp';
151
+ }
152
+ interface PhoneNumber {
153
+ verified_name: string;
154
+ display_phone_number: string;
155
+ id: string;
156
+ quality_rating: 'GREEN' | 'YELLOW' | 'RED' | 'NA';
157
+ }
158
+ interface ListPhoneNumbersResponse {
159
+ data: PhoneNumber[];
160
+ }
161
+
162
+ interface WABAApiClientOptions {
163
+ accessToken: string;
164
+ phoneNumberId: string;
165
+ apiVersion?: string;
166
+ baseUrl?: string;
167
+ }
168
+ /**
169
+ * Client for WhatsApp Business API outbound operations (sending messages, phone registration).
170
+ */
171
+ declare class WABAApiClient {
172
+ private readonly accessToken;
173
+ private readonly phoneNumberId;
174
+ private readonly apiVersion;
175
+ private readonly baseUrl;
176
+ constructor(options: WABAApiClientOptions);
177
+ /**
178
+ * Register phone number with WhatsApp Business API.
179
+ *
180
+ * @throws {WABAAuthError} - Authentication failure (invalid token)
181
+ * @throws {WABASendError} - Registration failure
182
+ * @throws {WABANetworkError} - Network/connection failures
183
+ */
184
+ registerPhone(pin: string): Promise<SuccessResponse>;
185
+ /**
186
+ * Deregister phone number from WhatsApp Business API.
187
+ *
188
+ * @throws {WABAAuthError} - Authentication failure (invalid token)
189
+ * @throws {WABASendError} - Deregistration failure
190
+ * @throws {WABANetworkError} - Network/connection failures
191
+ */
192
+ deregisterPhone(): Promise<SuccessResponse>;
193
+ /**
194
+ * List all phone numbers in a WhatsApp Business Account.
195
+ *
196
+ * @param wabaId - WhatsApp Business Account ID
197
+ * @throws {WABAAuthError} - Authentication failure (invalid token)
198
+ * @throws {WABASendError} - Request failure
199
+ * @throws {WABANetworkError} - Network/connection failures
200
+ */
201
+ listPhoneNumbers(wabaId: string): Promise<ListPhoneNumbersResponse>;
202
+ /**
203
+ * Send text message.
204
+ *
205
+ * @throws {WABAAuthError} - Authentication failure (invalid token)
206
+ * @throws {WABASendError} - Message sending failure
207
+ * @throws {WABANetworkError} - Network/connection failures
208
+ */
209
+ sendTextMessage(to: string, text: string, options?: {
210
+ previewUrl?: boolean;
211
+ context?: {
212
+ message_id: string;
213
+ };
214
+ }): Promise<SendMessageResponse>;
215
+ /**
216
+ * Send template message.
217
+ *
218
+ * @throws {WABAAuthError} - Authentication failure (invalid token)
219
+ * @throws {WABASendError} - Message sending failure
220
+ * @throws {WABANetworkError} - Network/connection failures
221
+ */
222
+ sendTemplateMessage(to: string, template: SendTemplateMessageRequest['template']): Promise<SendMessageResponse>;
223
+ /**
224
+ * Send generic message (accepts full message payload).
225
+ * Useful for sending any message type (image, video, document, interactive, etc.).
226
+ *
227
+ * @throws {WABAAuthError} - Authentication failure (invalid token)
228
+ * @throws {WABASendError} - Message sending failure
229
+ * @throws {WABANetworkError} - Network/connection failures
230
+ */
231
+ sendMessage(payload: MessagePayload): Promise<SendMessageResponse>;
232
+ private makeRequest;
233
+ }
234
+
235
+ /** Context object for replies and forwarded messages */
236
+ interface MessageContext {
237
+ /** Original sender (for replies) */
238
+ from?: string;
239
+ /** Original message ID */
240
+ id?: string;
241
+ forwarded?: boolean;
242
+ frequently_forwarded?: boolean;
243
+ /** Present for product enquiry messages */
244
+ referred_product?: {
245
+ catalog_id: string;
246
+ product_retailer_id: string;
247
+ };
248
+ }
249
+ /** Identity object for security notifications */
250
+ interface MessageIdentity {
251
+ /** State of acknowledgment for latest user_identity_changed system notification */
252
+ acknowledged: boolean;
253
+ /** Timestamp when the WhatsApp Business API detected the user potentially changed */
254
+ created_timestamp: string;
255
+ /** Identifier for the latest user_identity_changed system notification */
256
+ hash: string;
257
+ }
258
+ /** Base fields present on all incoming messages */
259
+ interface IncomingMessageBase {
260
+ /** Sender's phone number */
261
+ from: string;
262
+ /** Message ID (use for mark-as-read) */
263
+ id: string;
264
+ /** Unix epoch seconds as string */
265
+ timestamp: string;
266
+ /** Message type */
267
+ type: string;
268
+ /** Present if reply or forwarded */
269
+ context?: MessageContext;
270
+ /** Present if show_security_notifications is enabled in application settings */
271
+ identity?: MessageIdentity;
272
+ }
273
+ /** Text message */
274
+ interface TextMessage extends IncomingMessageBase {
275
+ type: 'text';
276
+ text: {
277
+ body: string;
278
+ };
279
+ }
280
+ /** Media object base (shared by image, audio, video, document, sticker) */
281
+ interface MediaObject {
282
+ id: string;
283
+ mime_type: string;
284
+ sha256: string;
285
+ caption?: string;
286
+ }
287
+ /** Image message */
288
+ interface ImageMessage extends IncomingMessageBase {
289
+ type: 'image';
290
+ image: MediaObject;
291
+ }
292
+ /** Audio message */
293
+ interface AudioMessage extends IncomingMessageBase {
294
+ type: 'audio';
295
+ audio: MediaObject & {
296
+ /** True if voice note */
297
+ voice?: boolean;
298
+ };
299
+ }
300
+ /** Video message */
301
+ interface VideoMessage extends IncomingMessageBase {
302
+ type: 'video';
303
+ video: MediaObject;
304
+ }
305
+ /** Document message */
306
+ interface DocumentMessage extends IncomingMessageBase {
307
+ type: 'document';
308
+ document: MediaObject & {
309
+ filename?: string;
310
+ };
311
+ }
312
+ /** Sticker message */
313
+ interface StickerMessage extends IncomingMessageBase {
314
+ type: 'sticker';
315
+ sticker: MediaObject & {
316
+ animated?: boolean;
317
+ };
318
+ }
319
+ /** Location message */
320
+ interface LocationMessage extends IncomingMessageBase {
321
+ type: 'location';
322
+ location: {
323
+ latitude: number;
324
+ longitude: number;
325
+ name?: string;
326
+ address?: string;
327
+ };
328
+ }
329
+ /** Contact in contacts message */
330
+ interface ContactCard {
331
+ name: {
332
+ formatted_name: string;
333
+ first_name?: string;
334
+ last_name?: string;
335
+ middle_name?: string;
336
+ suffix?: string;
337
+ prefix?: string;
338
+ };
339
+ phones?: Array<{
340
+ phone?: string;
341
+ type?: string;
342
+ wa_id?: string;
343
+ }>;
344
+ emails?: Array<{
345
+ email?: string;
346
+ type?: string;
347
+ }>;
348
+ addresses?: Array<{
349
+ street?: string;
350
+ city?: string;
351
+ state?: string;
352
+ zip?: string;
353
+ country?: string;
354
+ country_code?: string;
355
+ type?: string;
356
+ }>;
357
+ org?: {
358
+ company?: string;
359
+ department?: string;
360
+ title?: string;
361
+ };
362
+ urls?: Array<{
363
+ url?: string;
364
+ type?: string;
365
+ }>;
366
+ birthday?: string;
367
+ }
368
+ /** Contacts message */
369
+ interface ContactsMessage extends IncomingMessageBase {
370
+ type: 'contacts';
371
+ contacts: ContactCard[];
372
+ }
373
+ /** Button reply object */
374
+ interface ButtonReply {
375
+ id: string;
376
+ title: string;
377
+ }
378
+ /** List reply object */
379
+ interface ListReply {
380
+ id: string;
381
+ title: string;
382
+ description?: string;
383
+ }
384
+ /** Flow (NFM) reply object */
385
+ interface NfmReply {
386
+ /** JSON string containing the flow response data */
387
+ response_json: string;
388
+ /** Optional body text */
389
+ body?: string;
390
+ /** Flow name */
391
+ name?: string;
392
+ /** Flow token for tracking/correlation */
393
+ flow_token?: string;
394
+ }
395
+ /** Interactive message (button/list replies, flow responses) */
396
+ interface InteractiveMessage extends IncomingMessageBase {
397
+ type: 'interactive';
398
+ interactive: {
399
+ type: 'button_reply' | 'list_reply' | 'nfm_reply';
400
+ button_reply?: ButtonReply;
401
+ list_reply?: ListReply;
402
+ nfm_reply?: NfmReply;
403
+ };
404
+ }
405
+ /** Reaction message */
406
+ interface ReactionMessage extends IncomingMessageBase {
407
+ type: 'reaction';
408
+ reaction: {
409
+ message_id: string;
410
+ emoji: string;
411
+ };
412
+ }
413
+ /** Button message (quick reply button click) */
414
+ interface ButtonMessage extends IncomingMessageBase {
415
+ type: 'button';
416
+ button: {
417
+ text: string;
418
+ payload: string;
419
+ };
420
+ }
421
+ /** Order message */
422
+ interface OrderMessage extends IncomingMessageBase {
423
+ type: 'order';
424
+ order: {
425
+ catalog_id: string;
426
+ product_items: Array<{
427
+ product_retailer_id: string;
428
+ quantity: number;
429
+ item_price: number;
430
+ currency: string;
431
+ }>;
432
+ text?: string;
433
+ };
434
+ }
435
+ /** System message (number change, identity change) */
436
+ interface SystemMessage extends IncomingMessageBase {
437
+ type: 'system';
438
+ system: {
439
+ body: string;
440
+ type: 'user_changed_number' | 'user_identity_changed';
441
+ new_wa_id?: string;
442
+ identity?: string;
443
+ user?: string;
444
+ };
445
+ }
446
+ /** Referral message (click-to-WhatsApp ads) */
447
+ interface ReferralMessage extends IncomingMessageBase {
448
+ type: 'referral';
449
+ referral: {
450
+ source_url: string;
451
+ source_type: string;
452
+ source_id: string;
453
+ headline?: string;
454
+ body?: string;
455
+ media_type?: string;
456
+ image_url?: string;
457
+ video_url?: string;
458
+ thumbnail_url?: string;
459
+ };
460
+ }
461
+ /** Unsupported/unknown message type */
462
+ interface UnsupportedMessage extends IncomingMessageBase {
463
+ type: 'unsupported' | 'unknown';
464
+ errors?: Array<{
465
+ code: number;
466
+ title: string;
467
+ details?: string;
468
+ }>;
469
+ }
470
+ /** Union of all incoming message types */
471
+ type IncomingMessage = TextMessage | ImageMessage | AudioMessage | VideoMessage | DocumentMessage | StickerMessage | LocationMessage | ContactsMessage | InteractiveMessage | ReactionMessage | ButtonMessage | OrderMessage | SystemMessage | ReferralMessage | UnsupportedMessage;
472
+ /** Union of media message types */
473
+ type MediaMessage = ImageMessage | AudioMessage | VideoMessage | DocumentMessage | StickerMessage;
474
+ /** Discriminated union for message classification results */
475
+ type MessageClassification = {
476
+ type: 'text';
477
+ message: TextMessage;
478
+ } | {
479
+ type: 'image';
480
+ message: ImageMessage;
481
+ } | {
482
+ type: 'video';
483
+ message: VideoMessage;
484
+ } | {
485
+ type: 'audio';
486
+ message: AudioMessage;
487
+ } | {
488
+ type: 'document';
489
+ message: DocumentMessage;
490
+ } | {
491
+ type: 'sticker';
492
+ message: StickerMessage;
493
+ } | {
494
+ type: 'location';
495
+ message: LocationMessage;
496
+ } | {
497
+ type: 'contacts';
498
+ message: ContactsMessage;
499
+ } | {
500
+ type: 'interactive';
501
+ message: InteractiveMessage;
502
+ } | {
503
+ type: 'reaction';
504
+ message: ReactionMessage;
505
+ } | {
506
+ type: 'button';
507
+ message: ButtonMessage;
508
+ } | {
509
+ type: 'order';
510
+ message: OrderMessage;
511
+ } | {
512
+ type: 'system';
513
+ message: SystemMessage;
514
+ } | {
515
+ type: 'referral';
516
+ message: ReferralMessage;
517
+ } | {
518
+ type: 'unsupported';
519
+ message: UnsupportedMessage;
520
+ };
521
+
522
+ /** Top-level webhook payload from Meta */
523
+ interface WebhookPayload {
524
+ object: 'whatsapp_business_account';
525
+ entry: WebhookEntry[];
526
+ }
527
+ interface WebhookEntry {
528
+ /** WABA ID */
529
+ id: string;
530
+ changes: WebhookChange[];
531
+ }
532
+ interface WebhookChange {
533
+ value: WebhookValue;
534
+ field: string;
535
+ }
536
+ /** Union of possible webhook value types */
537
+ type WebhookValue = MessageWebhookValue | StatusWebhookValue | CallWebhookValue;
538
+ /** Contact info included in webhooks */
539
+ interface WebhookContact {
540
+ profile: {
541
+ /** Sender's profile name (optional per WABA docs) */
542
+ name?: string;
543
+ };
544
+ wa_id: string;
545
+ }
546
+ /** Metadata included in all webhook values */
547
+ interface WebhookMetadata {
548
+ display_phone_number: string;
549
+ phone_number_id: string;
550
+ }
551
+ /** Error object in webhooks */
552
+ interface WebhookError {
553
+ code: number;
554
+ title: string;
555
+ message?: string;
556
+ error_data?: {
557
+ details: string;
558
+ };
559
+ }
560
+ /** Webhook value for incoming messages */
561
+ interface MessageWebhookValue {
562
+ messaging_product: 'whatsapp';
563
+ metadata: WebhookMetadata;
564
+ contacts?: WebhookContact[];
565
+ messages?: IncomingMessage[];
566
+ errors?: WebhookError[];
567
+ }
568
+ /** Status update types */
569
+ type MessageStatus = 'sent' | 'delivered' | 'read' | 'failed' | 'deleted';
570
+ /** Conversation origin types */
571
+ type ConversationOriginType = 'business_initiated' | 'user_initiated' | 'referral_conversion';
572
+ /** Conversation object in status webhooks */
573
+ interface ConversationObject {
574
+ id: string;
575
+ origin: {
576
+ type: ConversationOriginType;
577
+ };
578
+ expiration_timestamp?: string;
579
+ }
580
+ /** Pricing model types */
581
+ type PricingModel = 'CBP' | 'NBP';
582
+ /** Pricing category types */
583
+ type PricingCategory = 'business_initiated' | 'user_initiated' | 'referral_conversion' | 'authentication' | 'marketing' | 'utility' | 'service';
584
+ /** Pricing object in status webhooks */
585
+ interface PricingObject {
586
+ billable: boolean;
587
+ pricing_model: PricingModel;
588
+ category: PricingCategory;
589
+ }
590
+ /** Individual status entry */
591
+ interface StatusEntry {
592
+ id: string;
593
+ recipient_id: string;
594
+ status: MessageStatus;
595
+ timestamp: string;
596
+ conversation?: ConversationObject;
597
+ pricing?: PricingObject;
598
+ errors?: WebhookError[];
599
+ }
600
+ /** Webhook value for message status updates */
601
+ interface StatusWebhookValue {
602
+ messaging_product: 'whatsapp';
603
+ metadata: WebhookMetadata;
604
+ statuses: StatusEntry[];
605
+ }
606
+ /** Call event types */
607
+ type CallEvent = 'connect' | 'terminate' | 'status';
608
+ /** Call entry in call webhooks */
609
+ interface CallEntry {
610
+ id: string;
611
+ from: string;
612
+ to: string;
613
+ /** Present on connect webhooks */
614
+ event?: CallEvent;
615
+ direction: 'USER_INITIATED' | 'BUSINESS_INITIATED';
616
+ timestamp: string;
617
+ session?: {
618
+ sdp_type: string;
619
+ sdp: string;
620
+ };
621
+ /** e.g. ['COMPLETED'] or ['FAILED'] on terminate */
622
+ status?: string[];
623
+ /** Present on terminate if connected */
624
+ start_time?: string;
625
+ end_time?: string;
626
+ /** Seconds, present on terminate if connected */
627
+ duration?: number;
628
+ /** Arbitrary tracking string that allows you to attach custom metadata to calls */
629
+ biz_opaque_callback_data?: string;
630
+ errors?: {
631
+ code: number;
632
+ message: string;
633
+ };
634
+ }
635
+ /** Webhook value for call events */
636
+ interface CallWebhookValue {
637
+ messaging_product: 'whatsapp';
638
+ metadata: WebhookMetadata;
639
+ contacts?: WebhookContact[];
640
+ calls: CallEntry[];
641
+ }
642
+ /** Discriminated union for webhook classification results */
643
+ type WebhookClassification = {
644
+ type: 'message';
645
+ payload: MessageWebhookValue;
646
+ } | {
647
+ type: 'status';
648
+ payload: StatusWebhookValue;
649
+ } | {
650
+ type: 'call';
651
+ payload: CallWebhookValue;
652
+ } | {
653
+ type: 'unknown';
654
+ payload: unknown;
655
+ };
656
+
657
+ /**
658
+ * Classifies a webhook payload into its type.
659
+ * Returns a discriminated union for type-safe handling.
660
+ */
661
+ declare function classifyWebhook(payload: WebhookPayload): WebhookClassification;
662
+
663
+ /**
664
+ * Classifies an incoming message by its type.
665
+ * Returns a discriminated union for type-safe handling.
666
+ */
667
+ declare function classifyMessage(message: IncomingMessage): MessageClassification;
668
+
669
+ interface VerifyWebhookSignatureOptions {
670
+ /** X-Hub-Signature-256 header value */
671
+ signature: string | undefined;
672
+ /** Raw request body (NOT parsed JSON) */
673
+ rawBody: Buffer | string;
674
+ /** Meta App Secret */
675
+ appSecret: string | undefined;
676
+ }
677
+ /**
678
+ * Verifies webhook signature using HMAC-SHA256.
679
+ * Uses timing-safe comparison to prevent timing attacks.
680
+ *
681
+ * @throws {WABASignatureError} If appSecret is not provided
682
+ * @returns true if signature is valid, false otherwise
683
+ */
684
+ declare function verifyWebhookSignature(options: VerifyWebhookSignatureOptions): boolean;
685
+
686
+ /**
687
+ * Type guard: returns true if message contains downloadable media.
688
+ * Narrows type to messages with image/audio/video/document/sticker.
689
+ */
690
+ declare function isMediaMessage(message: IncomingMessage): message is MediaMessage;
691
+ /**
692
+ * Extracts media ID from any media message type.
693
+ * Returns undefined if message has no media.
694
+ */
695
+ declare function extractMediaId(message: IncomingMessage): string | undefined;
696
+ interface ContactInfo {
697
+ waId: string;
698
+ profileName: string | undefined;
699
+ phoneNumberId: string;
700
+ }
701
+ /**
702
+ * Extracts sender info from webhook payload.
703
+ * Returns null if the webhook doesn't contain message contact info.
704
+ */
705
+ declare function getContactInfo(webhook: WebhookPayload): ContactInfo | null;
706
+ /**
707
+ * Parses message timestamp to Date object.
708
+ * WhatsApp timestamps are Unix epoch seconds as strings.
709
+ */
710
+ declare function getMessageTimestamp(message: IncomingMessage): Date;
711
+ /**
712
+ * Extracts message ID from message or status webhook.
713
+ * Returns null if not a message/status webhook or ID not present.
714
+ */
715
+ declare function getMessageId(webhook: WebhookPayload): string | null;
716
+ /**
717
+ * Extracts call ID from call webhook.
718
+ * Returns null if not a call webhook or ID not present.
719
+ */
720
+ declare function getCallId(webhook: WebhookPayload): string | null;
721
+
722
+ /** Base error class for all WABA errors */
723
+ declare class WABAError extends Error {
724
+ readonly code?: number | undefined;
725
+ readonly details?: unknown | undefined;
726
+ constructor(message: string, code?: number | undefined, details?: unknown | undefined);
727
+ }
728
+ /** Error for media-related failures (404, access denied) */
729
+ declare class WABAMediaError extends WABAError {
730
+ readonly mediaId: string;
731
+ constructor(message: string, mediaId: string, code?: number);
732
+ }
733
+ /** Error for network/connection failures */
734
+ declare class WABANetworkError extends WABAError {
735
+ readonly cause?: Error;
736
+ constructor(message: string, cause?: Error);
737
+ }
738
+ /** Error for invalid webhook signatures */
739
+ declare class WABASignatureError extends WABAError {
740
+ constructor(message?: string);
741
+ }
742
+ /** Error for configuration issues (missing values, invalid config) */
743
+ declare class WABAConfigError extends WABAError {
744
+ readonly field?: string | undefined;
745
+ constructor(message: string, field?: string | undefined);
746
+ }
747
+ /** Error for authentication failures */
748
+ declare class WABAAuthError extends WABAError {
749
+ readonly statusCode: number;
750
+ constructor(message: string, statusCode: number);
751
+ }
752
+ /** Error for message sending failures */
753
+ declare class WABASendError extends WABAError {
754
+ readonly statusCode: number;
755
+ readonly errorPayload: unknown;
756
+ constructor(message: string, statusCode: number, errorPayload: unknown);
757
+ }
758
+
759
+ export { type AudioMessage, type ButtonMessage, type ButtonReply, type CallEntry, type CallWebhookValue, type ContactCard, type ContactInfo, type ContactsMessage, type ConversationObject, type DeregisterPhoneRequest, type DocumentMessage, type GetMediaOptions, type ImageMessage, type IncomingMessage, type IncomingMessageBase, type InteractiveMessage, type ListPhoneNumbersResponse, type ListReply, type LocationMessage, type MediaBufferResult, type MediaMessage, type MediaMetadata, type MediaObject, type MediaStreamResult, type MessageClassification, type MessageContext, type MessagePayload, type MessageStatus, type MessageWebhookValue, type OrderMessage, type PhoneNumber, type PricingObject, type ReactionMessage, type ReferralMessage, type RegisterPhoneRequest, type SendMessageResponse, type SendTemplateMessageRequest, type SendTextMessageRequest, type StatusEntry, type StatusWebhookValue, type StickerMessage, type SuccessResponse, type SystemMessage, type TemplateComponent, type TemplateParameter, type TextMessage, type UnsupportedMessage, type VerifyWebhookSignatureOptions, type VideoMessage, WABAApiClient, type WABAApiClientOptions, WABAAuthError, WABAClient, type WABAClientOptions, WABAConfigError, WABAError, WABAMediaError, WABANetworkError, WABASendError, WABASignatureError, type WebhookChange, type WebhookClassification, type WebhookContact, type WebhookEntry, type WebhookError, type WebhookMetadata, type WebhookPayload, type WebhookValue, classifyMessage, classifyWebhook, extractMediaId, getCallId, getContactInfo, getMessageId, getMessageTimestamp, isMediaMessage, verifyWebhookSignature };