@great-detail/whatsapp
Version:
SDK for interfacing with WhatsApp Business Platform in Typescript or Node.js using the Cloud API, hosted by Meta.
1,625 lines (1,573 loc) • 52.7 kB
TypeScript
import * as ky from 'ky';
import { KyInstance, Options as Options$1 } from 'ky';
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
/**
* A Phone Number. **Not** a Phone Number ID.
*/
type PhoneNumberString = `+${string}` | (string & NonNullable<unknown>);
/**
* WhatsApp Phone Number ID.
*
* @since 7.0.0
*/
type PhoneNumberID = string;
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type GetBusinessProfileFields = {
about?: boolean;
address?: boolean;
description?: boolean;
email?: boolean;
profile_picture_url?: boolean;
websites?: boolean;
vertical?: boolean;
};
type GetBusinessProfileOptions<Fields extends GetBusinessProfileFields = object> = {
phoneNumberID: PhoneNumberID;
fields?: Fields;
};
type GetBusinessProfilePayload<Fields extends GetBusinessProfileFields = object> = {
data: [
{
about: Fields extends {
about: true;
} ? string : undefined;
address: Fields extends {
address: true;
} ? string : undefined;
description: Fields extends {
description: true;
} ? string : undefined;
email: Fields extends {
email: true;
} ? string : undefined;
messaging_product: "whatsapp";
profile_picture_url: Fields extends {
profile_picture_url: true;
} ? string : undefined;
vertical: Fields extends {
vertical: true;
} ? "" | (string & NonNullable<unknown>) : undefined;
websites: Fields extends {
websites: true;
} ? [string] | [string, string] | (string[] & NonNullable<unknown>) : undefined;
}
];
};
type UpdateBusinessProfileOptions = {
phoneNumberID: PhoneNumberID;
about?: string;
address?: string;
description?: string;
email?: string;
profile_picture_handle?: string;
vertical?: "" | (string & NonNullable<unknown>);
websites?: [string] | [string, string] | (string[] & NonNullable<unknown>);
};
type UpdateBusinessProfilePayload = {
success: boolean;
};
interface MethodOptions$4 {
request?: Options$1;
}
declare class BusinessProfile {
protected _transport: KyInstance;
constructor(_transport: KyInstance);
protected getEndpoint(phoneNumberID: PhoneNumberID): string;
getBusinessProfile<Fields extends GetBusinessProfileFields = object>({ phoneNumberID, fields, request, }: MethodOptions$4 & GetBusinessProfileOptions<Fields>): ky.ResponsePromise<GetBusinessProfilePayload<Fields>>;
updateBusinessProfile({ phoneNumberID, request, ...json }: MethodOptions$4 & UpdateBusinessProfileOptions): ky.ResponsePromise<UpdateBusinessProfilePayload>;
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type MediaID = string;
interface MediaUploadOptions {
file: Blob;
phoneNumberID: PhoneNumberID;
filename?: string;
mimeType: string;
}
type MediaUploadPayload = {
id: MediaID;
};
type MediaGetURLOptions = {
phoneNumberID?: PhoneNumberID;
mediaID: MediaID;
};
type MediaGetURLPayload = {
messaging_product: "whatsapp";
url: string;
mime_type: string;
sha256: string;
file_size: string | number;
id: MediaID;
};
type MediaDeleteOptions = {
phoneNumberID?: PhoneNumberID;
mediaID: MediaID;
};
type MediaDeletePayload = {
success: boolean;
};
interface MethodOptions$3 {
request?: Options$1;
}
interface DownloadOptions {
mediaURL: string;
}
declare class Media {
protected _transport: KyInstance;
constructor(_transport: KyInstance);
protected getEndpoint(phoneNumberID: PhoneNumberID): string;
/**
* Upload Media.
* All media files sent through this endpoint are encrypted and persist for
* 30 days, unless they are deleted earlier.
*/
upload({ phoneNumberID, file, filename, mimeType, request, }: MethodOptions$3 & MediaUploadOptions): ky.ResponsePromise<MediaUploadPayload>;
/**
* Retrieve Media URL.
* Use the returned URL to download the media file. Note that clicking this
* URL (i.e. performing a generic GET) will not return the media; you must
* include an access token.
*
* A successful response includes an object with a media url. The URL is only
* valid for 5 minutes.
*/
getURL({ mediaID, phoneNumberID, request, }: MethodOptions$3 & MediaGetURLOptions): ky.ResponsePromise<MediaGetURLPayload>;
delete({ mediaID, phoneNumberID, request, }: MethodOptions$3 & MediaDeleteOptions): ky.ResponsePromise<MediaDeletePayload>;
/**
* Download Media.
* All media URLs expire after 5 minutes —you need to retrieve the media URL
* again if it expires. If you directly click on the URL you get from a
* `/MEDIA_ID` GET call, you get an access error.
*
* If successful, you will receive the binary data of media saved in
* media_file, response headers contain a content-type header to indicate the
* mime type of returned data.
*
* If media fails to download, you will receive a `404 Not Found` response
* code. In that case, we recommend you try to retrieve a new media URL and
* download it again. If doing so doesn't resolve the issue, please try to
* renew the `ACCESS_TOKEN` then retry downloading the media.
*
* @see {@link https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media#supported-media-types}
* @example
* // Download Media and Write to a File
* const download = await sdk.media.download({ mediaURL });
* const file = await download.arrayBuffer();
* fs.writeFile("filename.ext", Buffer.from(file));
*/
download({ mediaURL, request }: MethodOptions$3 & DownloadOptions): ky.ResponsePromise<unknown>;
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
/**
* A WhatsApp End-User Account ID.
*/
type AccountID = string;
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type WhatsappError = {
code: number;
message?: string;
type: string;
title?: string;
error_data?: {
messaging_product: "whatsapp";
/**
* Error description and a description of the most likely reason for the
* error. May also contain information on how to address the error, such as
* which parameter is invalid or what values are acceptable.
*/
details: string;
};
/**
* Trace ID you can include when contacting Direct Support. The ID may help
* support to debug the error.
*/
fbtrace_id: string;
/**
* @deprecated Since Graph API v16.0.
*/
error_subcode?: number;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type CreateMessageContact = {
/**
* Full contact address(es) formatted as an addresses object.
*/
addresses: {
type: "HOME" | "WORK" | (string & NonNullable<unknown>);
/**
* Street number and name.
*
* @since 4.2.0
*/
street?: string;
/**
* City name.
*
* @since 4.2.0
*/
city?: string;
/**
* State abbreviation.
*
* @since 4.2.0
*/
state?: string;
/**
* ZIP code.
*
* @since 4.2.0
*/
zip?: string;
/**
* Full country name.
*
* @since 4.2.0
*/
country?: string;
/**
* Two-letter country abbreviation.
*
* @since 4.2.0
*/
country_code?: string;
}[];
/**
* YYYY-MM-DD formatted string.
*/
birthday?: `${number}${number}${number}${number}-${number}${number}-${number}${number}` | (string & NonNullable<unknown>);
/**
* Contact email address(es) formatted as an emails object.
*/
emails: {
type: "HOME" | "WORK" | (string & NonNullable<unknown>);
/**
* Email address.
*/
email?: string;
}[];
/**
* Full contact name formatted as a name object.
* This appears to fit the required fields pattern for VCF4 contact files.
*/
name: {
/**
* Full name, as it normally appears.
*/
formatted_name: string;
/**
* First name.
*/
first_name?: string;
/**
* Last name.
*
* @since 4.2.0
*/
last_name?: string;
/**
* Middle name.
*
* @since 4.2.0
*/
middle_name?: string;
/**
* Name suffix.
*
* @since 4.2.0
*/
suffix?: string;
/**
* Name prefix.
*
* @since 4.2.0
*/
prefix?: string;
};
org?: {
/**
* Name of the contact's company.
*/
company?: string;
/**
* Name of the contact's department.
*/
department?: string;
/**
* Contact's business title.
*/
title?: string;
};
phones?: {
type?: "CELL" | "MAIN" | "IPHONE" | "HOME" | "WORK" | (string & NonNullable<unknown>);
/**
* Automatically populated with the `wa_id` value as a formatted phone
* number.
*/
phone?: PhoneNumberString;
/**
* WhatsApp ID.
*/
wa_id?: AccountID;
}[];
urls: {
type?: "HOME" | "WORK" | (string & NonNullable<unknown>);
/**
* URL.
*
* @since 4.2.0
*/
url?: string;
}[];
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type CreateMessageLocation = {
/**
* Longitude of the location.
*/
longitude: number;
/**
* Latitude of the location.
*/
latitude: number;
/**
* Name of the location.
*/
name: string;
/**
* Address of the location.
*/
address: string;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type CreateMessageMedia = {
/**
* ID for the media file.
*/
id?: string;
/**
* Required when type is audio, document, image, sticker, or video and you
* are not using an uploaded media ID (i.e. you are hosting the media asset
* on your public server).
*
* The protocol and URL of the media to be sent. Use only with HTTP/HTTPS URLs.
*
* Do not use this field when message type is set to text.
*
* Cloud API users only:
*
* - See {@link https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages#media-http-caching}
* if you would like us to cache the media asset for future messages.
* - When we request the media asset from your server you must indicate the
* media's MIME type by including the `Content-Type` HTTP header. For
* example: `Content-Type: video/mp4`. See
* {@link https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media#supported-media-types}
* for a list of supported media and their MIME types.
*/
link?: string;
/**
* Media asset caption. Do not use with audio or sticker media.
*
* On-Premises API users:
*
* - For v2.41.2 or newer, this field is limited to 1024 characters.
* - Captions are currently not supported for `document` media.
*/
caption?: string;
/**
* Describes the filename for the specific document. Use only with document
* media.
*
* The extension of the filename will specify what format the document is
* displayed as in WhatsApp.
*/
filename?: string;
};
type EventNotificationMessageMedia = {
/**
* ID for the media file.
*
* @since 5.0.0
*/
id?: string;
/**
* Mime type of the media file.
*
* @since 5.0.0
*/
mime_type: string;
/**
* Media asset caption. Do not use with audio or sticker media.
*
* On-Premises API users:
*
* - For v2.41.2 or newer, this field is limited to 1024 characters.
* - Captions are currently not supported for `document` media.
*/
caption?: string;
/**
* Describes the filename for the specific document. Use only with document
* media.
*
* The extension of the filename will specify what format the document is
* displayed as in WhatsApp.
*/
filename?: string;
/**
* Image hash.
*/
sha256: string;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare enum MessageType {
Audio = "audio",// for audio messages.
Contacts = "contacts",// for contact messages.
Document = "document",// for document messages.
Image = "image",// for image messages.
Interactive = "interactive",// for list and reply button messages.
Location = "location",// for location messages.
Reaction = "sticker",// for reaction messages.
Sticker = "sticker",// for sticker messages.
/**
* Not supported for Outgoing Messages.
*/
System = "system",
/**
* Not supported for Outgoing Messages.
*/
Button = "button",
/**
* Not supported for Outgoing Messages.
*/
Order = "order",
Template = "template",// for template messages. Text and media (images and documents) message templates are supported.
Text = "text",// for text messages.
Video = "video"
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type MessageTemplateComponentNamedParameter = {
parameter_name: string;
};
type MessageTemplateComponentPositionalParameter = {
parameter_name?: never;
};
type MessageTemplateButtonTextParameter<T> = {
type: "text";
/**
* Developer-defined payload that is returned when the button is clicked in addition to the display text on the button.
*
* Required for `quick_reply` buttons.
*/
payload?: string;
text?: string;
} & T;
type MessageTemplateButtonPayloadParameter<T> = {
type: "payload";
/**
* Developer-defined payload that is returned when the button is clicked in addition to the display text on the button.
*
* Required for `quick_reply` buttons.
*/
payload?: string;
/**
* Developer-provided suffix that is appended to the predefined prefix URL in the template.
*
* Required for URL buttons.
*/
text?: string;
} & T;
type MessageTemplateTextParameter<T> = {
type: "text";
/**
* The message’s text. Character limit varies based on the following included component type.
*
* For the header component type:
* - 60 characters
*
* For the body component type:
* - 1024 characters if other component types are included
* - 32768 characters if body is the only component type included
*/
text: string;
} & T;
type MessageTemplateImageParameter<T> = {
type: MessageType.Image;
[MessageType.Image]: Omit<CreateMessageMedia, "caption">;
} & T;
type MessageTemplateDocumentParameter<T> = {
type: MessageType.Document;
[MessageType.Document]: Omit<CreateMessageMedia, "caption">;
} & T;
type MessageTemplateVideoParameter<T> = {
type: MessageType.Video;
[MessageType.Video]: Omit<CreateMessageMedia, "caption">;
} & T;
type MessageTemplateCurrencyParameter<T> = {
type: "currency";
currency: {
/** Default text if localization fails. */
fallback_value: string;
/** Currency code as defined in ISO 4217. */
code: string;
/** Amount multiplied by 1000. */
amount_1000: number;
};
} & T;
type MessageTemplateDateTimeParameter<T> = {
type: "date_time";
date_time: {
/** Default text. For Cloud API, we always use the fallback value, and we do not attempt to localize using other optional fields. */
fallback_value: string;
};
} & T;
type MessageTemplateHeaderLocationParameter<T> = {
type: "location";
location: {
latitude: string;
longitude: string;
name: string;
address: string;
};
} & T;
type MessageTemplateBodyParameter<T> = MessageTemplateTextParameter<T> | MessageTemplateImageParameter<T> | MessageTemplateDocumentParameter<T> | MessageTemplateVideoParameter<T> | MessageTemplateCurrencyParameter<T> | MessageTemplateDateTimeParameter<T>;
type MessageTemplateHeaderParameter<T> = MessageTemplateTextParameter<T> | MessageTemplateImageParameter<T> | MessageTemplateDocumentParameter<T> | MessageTemplateVideoParameter<T> | MessageTemplateCurrencyParameter<T> | MessageTemplateDateTimeParameter<T> | MessageTemplateHeaderLocationParameter<T>;
type MessageTemplateButtonParameter<T> = MessageTemplateButtonPayloadParameter<T> | MessageTemplateButtonTextParameter<T>;
type HeaderMessageComponent<T> = {
type: "header";
parameters: MessageTemplateHeaderParameter<T>[];
};
type BodyMessageComponent<T> = {
type: "body";
parameters: MessageTemplateBodyParameter<T>[];
};
type ButtonMessageComponent<T> = {
type: "button";
/** Numeric string */
index: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
} & ({
sub_type: "quick_reply";
parameters: (MessageTemplateButtonParameter<T> & {
payload: Required<MessageTemplateButtonParameter<T>["payload"]>;
})[];
} | {
sub_type: "url";
parameters: (MessageTemplateButtonParameter<T> & {
text: Required<MessageTemplateButtonParameter<T>["text"]>;
})[];
});
type MessageComponent<T> = HeaderMessageComponent<T> | BodyMessageComponent<T> | ButtonMessageComponent<T>;
type CreateMessageTemplate = {
/** Name of the template. */
name: string;
/** Specifies the language the template may be rendered in. */
language: {
/**
* The language policy the message should follow.
*
* @see https://developers.facebook.com/docs/whatsapp/api/messages/message-templates#language-policy-options
*/
policy: "deterministic";
/**
* The code of the language or locale to use.
*
* Accepts both language and language_locale formats (e.g., en and en_US).
*
* @see https://developers.facebook.com/docs/whatsapp/api/messages/message-templates#supported-languages
*/
code: string;
};
/** Array of components objects containing the parameters of the message. */
components: MessageComponent<MessageTemplateComponentNamedParameter>[] | MessageComponent<MessageTemplateComponentPositionalParameter>[];
/**
* Namespace of the template.
*
* @deprecated Used by On-Premises API Only
*/
namespace?: string;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type CreateMessageText = {
body: string;
preview_url?: boolean;
};
type EventNotificationMessageText = {
body: string;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
/**
* WhatsApp Message ID.
* This ID likely starts with `wamid.`.
*/
type MessageID = `wamid.${string}` | (string & NonNullable<unknown>);
type MessageStatusType = "read" | (string & NonNullable<unknown>);
type MessageRecipientType = "individual" | "group" | (string & NonNullable<unknown>);
type CreateMessageOptions = {
phoneNumberID: PhoneNumberID;
/**
* WhatsApp ID or phone number of the customer you want to send a message to.
*/
to: PhoneNumberID | PhoneNumberString;
/**
* Currently, you can only send messages to individuals.
*
* @default "individual"
* @see {@link https://developers.facebook.com/docs/graph-api/reference/whats-app-business-account-to-number-current-status/messages/#parameters}
*/
recipientType?: MessageRecipientType;
/**
* Required if replying to any message in the conversation.
*/
context?: {
inReplyTo: MessageID;
};
/**
* An arbitrary 256B string, useful for tracking. For example, you could pass
* the message template ID in this field to track your customer's journey
* starting from the first message you send. You could then track the ROI of
* different message template types to determine the most effective one.
*
* Any app subscribed to the messages webhook field on the WhatsApp Business
* Account can get this string, as it is included in statuses object within
* webhook payloads.
*
* Cloud API does not process this field, it just returns it as part of
* sent/delivered/read message webhooks.
*
* @since November 14, 2023
*/
biz_opaque_callback_data?: string;
[key: string]: unknown | undefined;
} & ({
type: MessageType.Audio;
[MessageType.Audio]: Omit<CreateMessageMedia, "caption">;
} | {
type: MessageType.Contacts;
[MessageType.Contacts]: CreateMessageContact[];
} | {
type: MessageType.Document;
[MessageType.Document]: CreateMessageMedia;
} | {
type: MessageType.Image;
[MessageType.Image]: CreateMessageMedia;
} | {
type: MessageType.Interactive;
[MessageType.Interactive]: unknown;
} | {
type: MessageType.Location;
[MessageType.Location]: CreateMessageLocation;
} | {
type: MessageType.Reaction;
[MessageType.Reaction]: Omit<CreateMessageMedia, "caption">;
} | {
type: MessageType.Sticker;
[MessageType.Sticker]: Omit<CreateMessageMedia, "caption">;
} | {
type: MessageType.Template;
[MessageType.Template]: CreateMessageTemplate;
} | {
type: MessageType.Text;
[MessageType.Text]: CreateMessageText;
} | {
type: MessageType.Video;
[MessageType.Video]: CreateMessageMedia;
} | {
type: string & NonNullable<unknown>;
});
type CreateMessagePayload = {
messaging_product: "whatsapp";
contacts: {
input: PhoneNumberString;
wa_id: AccountID;
}[];
messages: {
id: MessageID;
message_status: "accepted" | "held_for_quality_assessment";
}[];
error: WhatsappError;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type CreateStatusOptions = {
phoneNumberID: PhoneNumberID;
message_id: MessageID;
status: MessageStatusType;
typing_indicator?: {
type: "text";
};
[key: string]: unknown | undefined;
};
type CreateStatusPayload = {
success?: boolean;
error: WhatsappError;
};
interface MethodOptions$2 {
request?: Options$1;
}
declare class Message {
protected _transport: KyInstance;
constructor(_transport: KyInstance);
protected getEndpoint(phoneNumberID: PhoneNumberID): string;
/**
* Create a Status Message.
*
* ```ts
* const message = await sdk.message.createStatus({
* phoneNumberID: "123...809",
* message_id: "...",
* status: "read",
* typing_indicator: { type: "text" },
* });
* ```
*/
createStatus({ phoneNumberID, request, ...status }: MethodOptions$2 & CreateStatusOptions): ky.ResponsePromise<CreateStatusPayload>;
/**
* Create a Message.
*
* ```ts
* const message = await sdk.message.createMessage({
* phoneNumberID: "123...809",
* to: "1234567890",
* type: "text",
* text: { body: "Hello" },
* });
* ```
*/
createMessage({ to, phoneNumberID, context, recipientType, request, ...message }: MethodOptions$2 & CreateMessageOptions): ky.ResponsePromise<CreateMessagePayload>;
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type BusinessAccountID = string;
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type ListPhoneNumbersOptions = {
businessAccountID: BusinessAccountID;
sort?: string;
filtering?: string;
};
type ListPhoneNumbersPaylod = {
data: {
id: PhoneNumberID;
verified_name: string;
code_verification_status: "VERIFIED" | (string & NonNullable<unknown>);
display_phone_number: string;
quality_rating: string;
platform_type: string;
throughput: {
level: string;
};
last_onboarded_time?: string;
webhook_configuration: {
application?: string;
};
}[];
};
type GetPhoneNumberFields = {
name_status?: boolean;
};
type GetPhoneNumberOptions<Fields extends GetPhoneNumberFields = object> = {
phoneNumberID: PhoneNumberID;
fields?: Fields;
};
type GetPhoneNumberPayload<Fields extends GetPhoneNumberFields = object> = {
id: PhoneNumberID;
verified_name: string;
name_status: Fields extends {
name_status: true;
} ? "APPROVED" | "AVAILABLE_WITHOUT_REVIEW" | "DECLINED" | "EXPIRED" | "PENDING_REVIEW" | "NONE" | (string & NonNullable<unknown>) : undefined;
code_verification_status: "VERIFIED" | (string & NonNullable<unknown>);
display_phone_number: string;
quality_rating: string;
platform_type: string;
throughput: {
level: string;
};
last_onboarded_time?: string;
webhook_configuration: {
application?: string;
};
};
interface MethodOptions$1 {
request?: Options$1;
}
declare class PhoneNumbers {
protected _transport: KyInstance;
constructor(_transport: KyInstance);
getEndpoint(businessAccountID: BusinessAccountID): string;
getPhoneNumber<Fields extends GetPhoneNumberFields = object>({ phoneNumberID, fields, request, }: MethodOptions$1 & GetPhoneNumberOptions): ky.ResponsePromise<GetPhoneNumberPayload<Fields>>;
listPhoneNumbers({ businessAccountID, sort, filtering, request, }: MethodOptions$1 & ListPhoneNumbersOptions): ky.ResponsePromise<ListPhoneNumbersPaylod>;
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type CreateSubscriptionOptions = {
businessAccountID: BusinessAccountID;
};
type CreateSubscriptionPayload = {
success: boolean;
};
type ListSubscriptionsOptions = {
businessAccountID: BusinessAccountID;
};
type ListSubscriptionsPayload = {
data: {
whatsapp_business_api_data: {
id: string;
link?: string | null;
name: string;
};
}[];
};
interface MethodOptions {
request?: Options$1;
}
declare class SubscribedApps {
protected _transport: KyInstance;
constructor(_transport: KyInstance);
protected getEndpoint(businessAccountID: BusinessAccountID): string;
createSubscription({ businessAccountID, request, }: MethodOptions & CreateSubscriptionOptions): ky.ResponsePromise<CreateSubscriptionPayload>;
listSubscriptions({ businessAccountID, request, }: MethodOptions & ListSubscriptionsOptions): ky.ResponsePromise<ListSubscriptionsPayload>;
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type EventNotificationMessageIdentity = {
/**
* State of acknowledgment for the messages system customer_identity_changed.
*/
acknowledged: string;
/**
* The time when the WhatsApp Business Management API detected the customer
* may have changed their profile information.
*/
created_timestamp: string;
/**
* The ID for the messages system customer_identity_changed.
*/
hash: string;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type EventNotificationMessageReferral = {
/**
* The Meta URL that leads to the ad or post clicked by the customer. Opening
* this URL takes you to the ad viewed by your customer.
*/
source_url: string;
/**
* The type of the ad's source.
*/
source_type: "ad" | "post" | (string & NonNullable<unknown>);
/**
* Meta ID for an ad or a post.
*/
source_id: string;
/**
* Headline used in the ad or post.
*/
headline: string;
/**
* Body for the ad or post.
*/
body: string;
/**
* Media present in the ad or post.
*/
media_type: "image" | "video" | (string & NonNullable<unknown>);
/**
* URL of the image, when media_type is an image.
*/
image_url: URL;
/**
* URL of the video, when media_type is a video.
*/
video_url: URL;
/**
* URL for the thumbnail, when media_type is a video.
*/
thumbnail_url: URL;
/**
* Click ID generated by Meta for ads that click to WhatsApp.
*
* @since September 27, 2023
*/
ctwa_clid?: string;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type EventNotificationMessageSystem = {
/**
* Describes the change to the customer's identity or phone number.
*/
body: string;
/**
* Hash for the identity fetched from server.
*/
identity: string;
/**
* The WhatsApp ID for the customer prior to the update.
*/
customer: AccountID;
/**
* Type of system update.
*/
type: "customer_changed_number" | "customer_identity_changed.js";
/**
* New WhatsApp ID for the customer when their phone number is updated.
*
* @deprecated since Webhook v11.0
*/
new_wa_id: AccountID;
/**
* New WhatsApp ID for the customer when their phone number is updated.
*/
wa_id: AccountID;
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
type ConversationType = "authentication" | "marketing" | "utility" | "service" | "referral_conversation" | (string & NonNullable<unknown>);
type WebhookEventNotificationMessagesChanges = {
/**
* Notification type. Value will be messages.
*/
field: "messages";
/**
* A value object.
*/
value: {
/**
* Array of contact objects with information for the customer who sent a
* message to the business.
*/
contacts: {
/**
* The customer's WhatsApp ID. A business can respond to a customer using
* this ID. This ID may not match the customer's phone number, which is
* returned by the API as input when sending a message to the customer.
*/
wa_id: AccountID;
/**
* Additional unique, alphanumeric identifier for a WhatsApp user.
*/
user_id?: string;
/**
* A customer profile object.
*/
profile: {
/**
* The customer's name.
*/
name: string;
};
}[];
/**
* An array of error objects describing the error.
*/
errors: WhatsappError[];
/**
* Product used to send the message. Value is always whatsapp.
*
* @default 'whatsapp'
*/
messaging_product: "whatsapp";
/**
* Information about a message received by the business that is subscribed to
* the webhook.
*/
messages?: ({
/**
* The ID for the message that was received by the business. You could use
* messages endpoint to mark this specific message as read.
*/
id: MessageID;
/**
* Unix timestamp indicating when the WhatsApp server received the message
* from the customer.
*/
timestamp: string;
/**
* The customer's WhatsApp ID. A business can respond to a customer using
* this ID. This ID may not match the customer's phone number, which is
* returned by the API as input when sending a message to the customer.
*/
from: AccountID;
/**
* Context object. Only included when a user replies or interacts with one of
* your messages.
*/
context?: {
/**
* Set to true if the message received by the business has been forwarded.
*/
forwarded: boolean;
/**
* Set to true if the message received by the business has been forwarded
* more than 5 times.
*/
frequently_forwarded: boolean;
/**
* The WhatsApp ID for the customer who replied to an inbound message.
*/
from: AccountID;
/**
* The message ID for the sent message for an inbound reply.
*/
id: MessageID;
/**
* Referred product object describing the product the user is requesting
* information about. You must parse this value if you support Product
* Enquiry Messages.
*/
referred_product: {
/**
* Unique identifier of the Meta catalog linked to the WhatsApp Business
* Account.
*/
catalog_id: string;
/**
* Unique identifier of the product in a catalog.
*/
product_retailer_id: string;
};
};
/**
* An array of error objects describing the error.
*
* @since 4.2.0
*/
errors?: WhatsappError[];
/**
* An identity object. Webhook is triggered when a customer's phone number or
* profile information has been updated.
*/
identity: EventNotificationMessageIdentity;
/**
* Referral object. When a customer clicks an ad that redirects to WhatsApp,
* this object is included in the messages object.
*/
referral?: EventNotificationMessageReferral;
} & ({
type: MessageType.Audio;
[MessageType.Audio]: Omit<EventNotificationMessageMedia, "caption" | "filename" | "sha256">;
} | {
type: MessageType.Button;
[MessageType.Button]: {
payload: string;
text: string;
};
} | {
type: MessageType.Contacts;
[MessageType.Contacts]: unknown;
} | {
type: MessageType.Document;
[MessageType.Document]: EventNotificationMessageMedia;
} | {
type: MessageType.Image;
[MessageType.Image]: EventNotificationMessageMedia;
} | {
type: MessageType.Interactive;
[MessageType.Interactive]: unknown;
} | {
type: MessageType.Order;
[MessageType.Order]: unknown;
} | {
type: MessageType.Location;
[MessageType.Location]: unknown;
} | {
type: MessageType.Reaction | MessageType.Sticker;
[MessageType.Sticker]: Omit<EventNotificationMessageMedia, "caption" | "filename"> & {
animated: boolean;
};
} | {
type: MessageType.Text;
[MessageType.Text]: EventNotificationMessageText;
} | {
type: MessageType.Video;
[MessageType.Video]: Omit<EventNotificationMessageMedia, "filename">;
} | {
type: MessageType.System;
/**
* When messages type is set to system, a customer has updated their phone
* number or profile information, this object is included in the messages
* object.
*/
[MessageType.System]: EventNotificationMessageSystem;
}))[];
/**
* A metadata object describing the business subscribed to the webhook.
*/
metadata: {
/**
* The phone number that is displayed for a business.
*/
display_phone_number: PhoneNumberString;
/**
* ID for the phone number. A business can respond to a message using this
* ID.
*/
phone_number_id: PhoneNumberID;
};
/**
* Status object for a message that was sent by the business that is
* subscribed to the webhook.
*/
statuses?: {
/**
* The ID for the message that the business that is subscribed to the
* webhooks sent to a customer.
*/
id: MessageID;
/**
* The customer's WhatsApp ID. A business can respond to a customer using
* this ID. This ID may not match the customer's phone number, which is
* returned by the API as input when sending a message to the customer.
*/
recipient_id: AccountID;
/**
* For a status to be read, it must have been delivered. In some scenarios,
* such as when a user is in the chat screen and a message arrives, the
* message is delivered and read almost simultaneously. In this or other
* similar scenarios, the delivered notification will not be sent back, as it
* is implied that a message has been delivered if it has been read. The
* reason for this behavior is internal optimization.
*/
status: "delivered" | "read" | "sent" | "failed";
/**
* Date for the status message.
*/
timestamp: number;
/**
* An object containing pricing information.
*/
pricing: {
/**
* Indicates the conversation category.
*
* @since 4.2.0
*/
category: ConversationType;
/**
* Type of pricing model used by the business.
*/
pricing_model: "CBP" | (string & NonNullable<unknown>);
/**
* Indicates if the given message or conversation is billable. Default is
* true for all conversations, including those inside your free tier limit,
* except those initiated from free entry points. Free entry point
* conversation are not billable, false. You will not be charged for free
* tier limit conversations, but they are considered billable and will be
* reflected on your invoice.
*
* @deprecated
*/
billable: boolean;
};
/**
* Information about the conversation.
*/
conversation: {
/**
* Represents the ID of the conversation the given status notification
* belongs to.
*/
id: string;
/**
* Date when the conversation expires. This field is only present for
* messages with a `status` set to `sent`.
*/
expiration_timestamp?: number;
/**
* Describes conversation category
*/
origin: {
/**
* Indicates conversation category. This can also be referred to as a
* conversation entry point.
*/
type: ConversationType;
};
};
/**
* Arbitrary string included in sent message.
*/
biz_opaque_callback_data?: string;
}[];
};
};
type WebhookEventNotificationAccountUpdateChanges = {
field: "account_update";
value: {
event: "PARTNER_APP_INSTALLED" | (string & NonNullable<unknown>);
waba_info: {
waba_id: AccountID;
owner_business_id: BusinessAccountID;
partner_app_id: string;
};
};
};
type WebhookEventNotification = {
/**
* The specific webhook a business is subscribed to. The webhook is
* whatsapp_business_account.
*/
object: string;
/**
* An array of entry objects.
*/
entry: {
/**
* The WhatsApp Business Account ID for the business that is subscribed to
* the webhook.
*/
id: BusinessAccountID;
/**
* An array of change objects.
*/
changes: (WebhookEventNotificationMessagesChanges | WebhookEventNotificationAccountUpdateChanges)[];
}[];
};
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class WebhookError extends Error {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class IncorrectMethodWebhookError extends WebhookError {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class InvalidHubChallengeWebhookError extends WebhookError {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class InvalidHubModeWebhookError extends WebhookError {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class InvalidHubSignatureWebhookError extends WebhookError {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class InvalidHubVerifyTokenWebhookError extends WebhookError {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
declare class MissingBodyWebhookError extends WebhookError {
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
interface IncomingRequest {
method: string;
query: Record<string, string>;
body?: string;
headers: Record<string, string>;
}
declare class Webhook {
errors: {
WebhookError: typeof WebhookError;
IncorrectMethodWebhookError: typeof IncorrectMethodWebhookError;
InvalidHubChallengeWebhookError: typeof InvalidHubChallengeWebhookError;
InvalidHubModeWebhookError: typeof InvalidHubModeWebhookError;
InvalidHubSignatureWebhookError: typeof InvalidHubSignatureWebhookError;
InvalidHubVerifyTokenWebhookError: typeof InvalidHubVerifyTokenWebhookError;
MissingBodyWebhookError: typeof MissingBodyWebhookError;
};
/**
* Handle a Registration Webhook Request.
* The handler for `GET` requests to your webhook endpoint. A registration
* request is when WhatsApp sends a GET request to your webhook endpoint to
* verify that it is valid. The challenge should be returned if valid.
*
* **ExpressJS**:
*
* ```ts
* app.get(
* "/path/to/webhook",
* async (req, res) => {
* const reg = await sdk.webhook.register({
* method: request.method,
* query: req.query,
* body: req.body,
* headers: req.headers,
* });
* // DIY: Check the reg.verifyToken value
* if (reg.verifyToken !== "abcd") {
* return res.end(reg.reject());
* }
* return res.end(reg.accept());
* }
* );
* ```
*
* **Fastify**:
*
* ```ts
* fastify.route({
* method: "GET",
* url: "/path/to/webhook",
* handler: (request, reply) => { *
* const reg = await sdk.webhook.register({
* method: request.method,
* query: request.query,
* body: undefined,
* headers: request.headers,
* });
* // DIY: Check the reg.verifyToken value
* if (reg.verifyToken !== "abcd") {
* return reply.send(reg.reject());
* }
* return reply.send(reg.accept());
* }
* });
* ```
*
* @throws {WebhookError}
*/
register(request: IncomingRequest): Promise<{
verifyToken: string;
challenge: string;
accept: () => string;
reject: () => void;
}>;
/**
* Handle an Event Notification Webhook Request.
* The handler for `POST` requests to your webhook endpoint.
*
* **ExpressJS**:
*
* ```ts
* app.use(express.raw()); // Important <-
* app.post(
* "/path/to/webhook",
* async (req, res) => {
* const event = sdk.webhook.eventNotification({
* method: request.method,
* query: req.query,
* body: req.body.toString(),
* headers: req.headers,
* });
* // DIY: Load the Meta App Secret
* event.verifySignature("abcd-app-secret");
* // Non-200 status codes will be retried
* // You may want to use the dreaded "successful error"
* if (someFailedCondition) {
* res.status(400);
* return res.end();
* }
* return res.end(event.accept());
* }
* );
* ```
*
* **Fastify**:
*
* ```ts
* // See: https://github.com/fastify/fastify/issues/707#issuecomment-817224931
* fastify.addContentTypeParser("application/json", { parseAs: "buffer" }, (_req, body, done) => {
* done(null, body);
* });
*
* fastify.route({
* method: "POST",
* url: "/path/to/webhook",
* handler: (request, reply) => {
* // This SDK handles inbound webhook requests from a string for signature verification
* assert(Buffer.isBuffer(request.body) || typeof request.body === "string");
* const body = request.body.toString();
*
* const event = sdk.webhook.eventNotification({
* method: request.method,
* query: request.query,
* body,
* headers: request.headers,
* });
* // DIY: Load the Meta App Secret
* event.verifySignature("abcd-app-secret");
* // Non-200 status codes will be retried
* // You may want to use the dreaded "successful error"
* if (someFailedCondition) {
* return reply.code(400).send();
* }
* return reply.send(event.accept());
* }
* });
* ```
*/
eventNotification(request: IncomingRequest): Promise<{
eventNotification: WebhookEventNotification;
signature: {
sha1: {
value: string;
getCalculatedSignature: (appSecret: string) => string;
check: (appSecret: string) => boolean;
};
sha256: {
value: string;
getCalculatedSignature: (appSecret: string) => string;
check: (appSecret: string) => boolean;
};
};
checkSignature: (appSecret: string) => boolean;
verifySignature(appSecret: string): void;
accept: () => void;
}>;
}
/**
* WhatsApp NodeJS SDK.
*
* @author Great Detail Ltd <info@greatdetail.com>
* @author Dom Webber <dom.webber@hotmail.com>
* @see https://greatdetail.com
*/
interface Options {
prefixUrl?: string;
graphVersion?: `v${string}` | (string & NonNullable<unknown>);
request?: Omit<Options$1,