‹ Back to blog

The (Missing) WhatsApp webhook API types

I am working on a project that involves integrating with the WhatsApp Business API, and I noticed that there are no official TypeScript types for the webhook API. The documentation while detailed, lacks (or i could not find) the type definitions that would make it easier to work with the API in a type-safe manner.

So, I decided to create my own minimal set of types to help me with the integration.

Reverse engineering the webhook payload

The process was pretty simple: 1 - In my app webhook endpoint, i saved the received payloads to a database 2 - From this sample i created the types using a JSON to TypeScript converter 3 - I then refined the types to make them more readable and easier to work with.

Some notes:

  • The types are not exhaustive, they only cover the message types that I needed for my project i.e, ‘messages’ and ‘message_template_status_update’.
  • My go to JSON to Typescript converter was from Transform.Tools which is based on json_typegen. But is lacking creation of enum / union types from fields with repeatable values. Fortunately i found quicktype that supports this feature.

The types

export interface NotificationPayload {
object: "whatsapp_business_account";
entry: Entry[];
}
export interface Entry {
id: string;
changes: Change[];
}
export type Change = MessagesChange | MessageTemplateStatusUpdateChange;
export interface MessagesChange {
field: "messages";
value: MessagesValue;
}
export interface MessageTemplateStatusUpdateChange {
field: "message_template_status_update";
value: MessageTemplateStatusUpdateValue;
}
export interface MessageTemplateStatusUpdateValue {
reason: string;
message_template_name: string;
event: string;
message_template_language: string;
message_template_id: number;
}
export interface MessagesValue {
metadata: Metadata;
messaging_product: MessagingProduct;
statuses?: StatusElement[];
messages?: Message[];
contacts?: Contact[];
}
export interface Contact {
profile: Profile;
wa_id: string;
}
export interface Profile {
name: string;
}
export interface Message {
from: string;
id: string;
text?: Text;
type: string;
timestamp: string;
sticker?: Sticker;
}
export interface Sticker {
sha256: string;
mime_type: string;
animated: boolean;
id: string;
}
export interface Text {
body: string;
}
export type MessagingProduct = "whatsapp";
export interface Metadata {
phone_number_id: string;
display_phone_number: string;
}
export interface StatusElement {
biz_opaque_callback_data?: string;
id: string;
conversation?: Conversation;
pricing?: Pricing;
status: StatusEnum;
timestamp: string;
recipient_id: string;
errors?: Error[];
}
export interface Conversation {
origin: Origin;
id: string;
expiration_timestamp?: string;
}
export interface Origin {
type: Category;
}
export type Category = "marketing" | "utility";
export interface Error {
code: number;
title: string;
message: string;
error_data: ErrorData;
}
export interface ErrorData {
details: string;
}
export interface Pricing {
pricing_model: PricingModel;
category: Category;
billable: boolean;
}
export type PricingModel = "CBP";
export type StatusEnum = "delivered" | "failed" | "read" | "sent";