/** * WhatsApp Cloud API client. * * Wraps Meta's Graph API for sending messages, marking-read, downloading media. * All `to` numbers are E.164 without `+` (Meta convention). * * Docs: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages */ import type { ButtonsPayload, CtaUrlPayload } from '../types.js'; export interface WhatsAppClientOptions { endpoint: string; token: string; graphBase?: string; } export interface ContactCard { name: { formatted_name: string; first_name: string; }; phones: Array<{ phone: string; type?: string; wa_id?: string; }>; org?: { company?: string; }; } export interface TemplatePayload { name: string; language?: string; components?: unknown[]; } export interface AuthenticationTemplateOptions { name: string; language?: string; /** Zero-based index of the URL button that carries the code. Default 0. */ buttonIndex?: number; } /** * v0.17: options for `sendUtilityTemplate`. UTILITY templates cover most * transactional notifications (order updates, appointment confirmations, * lead alerts). Meta pricing tier: mid (~R$0.04-0.05 in BR as of Jul/2025), * cheaper than MARKETING (~R$0.31-0.38). */ export interface UtilityTemplateOptions { name: string; language?: string; /** * Positional {{1}}, {{2}}, ... parameters for the body. Order matters — * Meta expects the same order as the placeholders in the approved template. * Values are sent as `{type:'text', text}`; convert non-strings yourself. */ bodyParams?: string[]; /** * URL-button dynamic suffix ({{1}} in the button URL). When set, the * template MUST have a URL button of type dynamic. When absent, no * button component is sent (the template's static URL button, if any, * still works). */ urlButtonSuffix?: string; /** Zero-based index of the URL button that carries the suffix. Default 0. */ buttonIndex?: number; } export declare class WhatsAppClient { readonly endpoint: string; readonly token: string; readonly graphBase: string; readonly authString: string; constructor({ endpoint, token, graphBase }: WhatsAppClientOptions); sendText(to: string, body: string, { previewUrl, inReplyToWamid }?: { previewUrl?: boolean; inReplyToWamid?: string | null; }): Promise; sendButtons(to: string, { body, footer, buttons }: ButtonsPayload): Promise; sendCtaUrl(to: string, { body, displayText, url }: CtaUrlPayload): Promise; sendImageUrl(to: string, { url, caption }: { url: string; caption?: string; }): Promise; sendVideoUrl(to: string, { url, caption }: { url: string; caption?: string; }): Promise; sendAudioUrl(to: string, { url }: { url: string; }): Promise; sendContact(to: string, contact: ContactCard): Promise; sendTemplate(to: string, { name, language, components }: TemplatePayload): Promise; markRead(wamid: string, { typing }?: { typing?: boolean; }): Promise; /** * v0.16: send a Meta AUTHENTICATION-category template (the "your code is * XXXXXX" flow). Encodes the non-obvious Meta rule that the OTP code * MUST appear in BOTH the body parameter AND the URL button parameter — * miss one and the "Copy code" button doesn't populate correctly. * * The template itself must be pre-approved by Meta in the * AUTHENTICATION category with a body {{1}} placeholder + a copy-code * URL button. See `docs/META_SETUP.md` for the template shape. * * await client.sendAuthenticationTemplate('5511999999999', '482913', { * name: 'portal_otp', * language: 'pt_BR', * }); * * Pairs with v0.13's `generateOtpCode` + `hashOtpCode` for a full * portal-OTP flow. */ sendAuthenticationTemplate(to: string, code: string, opts: AuthenticationTemplateOptions): Promise; /** * v0.17: send a Meta UTILITY-category template with body params + optional * dynamic URL-button suffix. Sibling of `sendAuthenticationTemplate`. * * The template must be pre-approved by Meta in the UTILITY category with * a body containing `{{1}} {{2}} ...` placeholders in the exact order you * pass `bodyParams`. If your template has a URL button whose href ends * in `{{1}}`, set `urlButtonSuffix` — miss it and Meta returns 400. * * await client.sendUtilityTemplate(brokerPhone, { * name: 'lead_notification', * language: 'pt_BR', * bodyParams: [ * listing.title.slice(0, 60), * lead.name.slice(0, 60), * lead.phone.slice(0, 30), * (lead.message ?? '(sem mensagem)').slice(0, 250), * ], * urlButtonSuffix: redirectToken, * }); * * See `docs/META_SETUP.md#creating-a-utility-template-with-body--url-button` * for the template shape you need to register. */ sendUtilityTemplate(to: string, opts: UtilityTemplateOptions): Promise; downloadMedia(mediaId: string): Promise; /** * v0.15: download variant that also returns the metadata Meta hands out * (mime_type, sha256, file_size). Right for pipelines that put the bytes * into R2 with the correct `contentType` instead of guessing. */ downloadMediaWithMeta(mediaId: string): Promise<{ stream: ReadableStream; mimeType?: string; sha256?: string; fileSize?: number; } | null>; send(message: Record): Promise; } //# sourceMappingURL=whatsapp.d.ts.map