
Security News
PyPI Expands Trusted Publishing to GitLab Self-Managed as Adoption Passes 25 Percent
PyPI adds Trusted Publishing support for GitLab Self-Managed as adoption reaches 25% of uploads
whatsapp-cloud-api-types
Advanced tools
TypeScript type definitions, Zod schemas, and a fully-typed API client for the WhatsApp Business Cloud API.
bun add whatsapp-cloud-api-types zod
or with npm:
npm install whatsapp-cloud-api-types zod
import { WhatsAppCloudAPI } from 'whatsapp-cloud-api-types'
const client = new WhatsAppCloudAPI({
accessToken: process.env.WHATSAPP_ACCESS_TOKEN!,
phoneNumberId: process.env.WHATSAPP_PHONE_NUMBER_ID!,
})
// Send a text message
await client.messages.sendText('1234567890', 'Hello, World!')
// Send an image
await client.messages.sendImage(
'1234567890',
{ link: 'https://example.com/image.jpg' },
'Check this out!'
)
// Send interactive buttons
await client.messages.sendInteractiveButtons('1234567890', {
type: 'button',
body: { text: 'Choose an option' },
action: {
buttons: [
{ type: 'reply', reply: { id: 'yes', title: 'Yes' } },
{ type: 'reply', reply: { id: 'no', title: 'No' } }
]
}
})
// Send CTA URL button
await client.messages.sendCtaUrl('1234567890', {
type: 'cta_url',
body: { text: 'Visit our website for more information!' },
action: {
name: 'cta_url',
parameters: {
display_text: 'Visit Website',
url: 'https://example.com'
}
}
})
// Upload and send media
const media = await client.media.upload(file, 'image/jpeg')
await client.messages.sendImage('1234567890', { id: media.id })
// Get business profile
const profile = await client.business.getProfile()
// Manage WhatsApp Business Accounts
const waba = await client.waba.getFirst()
const ownedWabas = await client.waba.getOwned()
// Manage phone numbers
const numbers = await client.phoneNumbers.list(waba!.id)
const phoneNumber = await client.phoneNumbers.get('PHONE_NUMBER_ID')
// Configure webhooks
await client.webhooks.subscribe(waba!.id, {
override_callback_uri: 'https://myapp.com/webhook',
verify_token: 'my-secret-token',
})
📖 Complete API Client Documentation →
This library provides Zod schemas for the following WhatsApp Cloud API webhooks:
messages field)All incoming message types and status updates are fully supported:
Message Types:
Additional Features:
Template Webhooks:
Type-safe schemas for WhatsApp Business Account (WABA) subscription management:
Use the unified schema to automatically validate and parse any webhook:
import { WhatsAppWebhookSchema } from 'whatsapp-cloud-api-types'
// In your webhook endpoint (Express example)
app.post('/webhook', (req, res) => {
try {
const webhook = WhatsAppWebhookSchema.parse(req.body)
// TypeScript knows the structure
webhook.entry.forEach(entry => {
entry.changes.forEach(change => {
if (change.field === 'messages') {
// Handle incoming messages
const messages = change.value.messages
const statuses = change.value.statuses
}
})
})
res.sendStatus(200)
} catch (error) {
console.error('Invalid webhook payload:', error)
res.sendStatus(400)
}
})
For better type inference, use specific webhook schemas:
import { MessagesWebhookSchema } from 'whatsapp-cloud-api-types'
const webhook = MessagesWebhookSchema.parse(req.body)
webhook.entry.forEach(entry => {
entry.changes.forEach(change => {
// Handle incoming messages
change.value.messages?.forEach(message => {
console.log(`Message from ${message.from}: ${message.text?.body}`)
// Type-safe access to different message types
switch (message.type) {
case 'text':
console.log('Text:', message.text?.body)
break
case 'image':
console.log('Image ID:', message.image?.id)
break
case 'interactive':
console.log('Button clicked:', message.interactive?.button_reply?.title)
break
}
})
// Handle message status updates
change.value.statuses?.forEach(status => {
console.log(`Message ${status.id} is now ${status.status}`)
})
})
})
import { MessageTemplateStatusUpdateWebhookSchema } from 'whatsapp-cloud-api-types'
const webhook = MessageTemplateStatusUpdateWebhookSchema.parse(req.body)
webhook.entry.forEach(entry => {
entry.changes.forEach(change => {
const { event, message_template_name, reason } = change.value
switch (event) {
case 'APPROVED':
console.log(`Template ${message_template_name} was approved!`)
break
case 'REJECTED':
console.log(`Template ${message_template_name} was rejected. Reason: ${reason}`)
break
case 'DISABLED':
console.log(`Template ${message_template_name} was disabled`)
if (change.value.disable_info) {
console.log(`Disabled on: ${new Date(change.value.disable_info.disable_date * 1000)}`)
}
break
}
})
})
import { MessageTemplateQualityUpdateWebhookSchema } from 'whatsapp-cloud-api-types'
const webhook = MessageTemplateQualityUpdateWebhookSchema.parse(req.body)
webhook.entry.forEach(entry => {
entry.changes.forEach(change => {
const { message_template_name, previous_quality_score, new_quality_score } = change.value
console.log(`Template "${message_template_name}" quality changed from ${previous_quality_score} to ${new_quality_score}`)
if (new_quality_score === 'RED') {
console.warn('⚠️ Template quality is now RED! Consider reviewing your template.')
}
})
})
import { MessageTemplateComponentsUpdateWebhookSchema } from 'whatsapp-cloud-api-types'
const webhook = MessageTemplateComponentsUpdateWebhookSchema.parse(req.body)
webhook.entry.forEach(entry => {
entry.changes.forEach(change => {
const template = change.value
console.log(`Template "${template.message_template_name}" was updated`)
console.log('Body:', template.message_template_element)
if (template.message_template_title) {
console.log('Header:', template.message_template_title)
}
if (template.message_template_buttons) {
console.log('Buttons:', template.message_template_buttons.map(b => b.message_template_button_text))
}
})
})
import { TemplateCategoryUpdateWebhookSchema } from 'whatsapp-cloud-api-types'
const webhook = TemplateCategoryUpdateWebhookSchema.parse(req.body)
webhook.entry.forEach(entry => {
entry.changes.forEach(change => {
const value = change.value
// Check if it's an impending change notification
if ('correct_category' in value) {
console.log(`Template "${value.message_template_name}" will be recategorized from ${value.new_category} to ${value.correct_category} in 24 hours`)
} else {
console.log(`Template "${value.message_template_name}" was recategorized from ${value.previous_category} to ${value.new_category}`)
}
})
})
Use Zod's safeParse for safe validation:
import { WhatsAppWebhookSchema } from 'whatsapp-cloud-api-types'
app.post('/webhook', (req, res) => {
const result = WhatsAppWebhookSchema.safeParse(req.body)
if (!result.success) {
console.error('Validation failed:', result.error.issues)
return res.sendStatus(400)
}
const webhook = result.data
// Process webhook...
res.sendStatus(200)
})
Use TypeScript's discriminated unions to handle different webhook types:
import { WhatsAppWebhook } from 'whatsapp-cloud-api-types'
function handleWebhook(webhook: WhatsAppWebhook) {
const change = webhook.entry[0].changes[0]
switch (change.field) {
case 'messages':
handleMessages(change.value)
break
case 'message_template_status_update':
handleTemplateStatusUpdate(change.value)
break
case 'template_category_update':
handleTemplateCategoryUpdate(change.value)
break
// TypeScript ensures you handle all cases
}
}
import type {
Message,
Status,
TemplateStatusEvent,
TemplateQualityScore
} from 'whatsapp-cloud-api-types'
function processMessage(message: Message) {
if (message.type === 'text') {
return message.text?.body
}
// TypeScript knows the structure
}
function checkQuality(score: TemplateQualityScore) {
return score === 'GREEN' || score === 'YELLOW'
}
import { SubscribeToWABAResponseSchema } from 'whatsapp-cloud-api-types'
const response = await fetch(
`https://graph.facebook.com/v18.0/${wabaId}/subscribed_apps`,
{
method: 'POST',
headers: { Authorization: `Bearer ${accessToken}` }
}
)
const result = SubscribeToWABAResponseSchema.parse(await response.json())
console.log('Subscribed:', result.success)
import { GetSubscriptionsResponseSchema } from 'whatsapp-cloud-api-types'
const response = await fetch(
`https://graph.facebook.com/v18.0/${wabaId}/subscribed_apps`,
{
method: 'GET',
headers: { Authorization: `Bearer ${accessToken}` }
}
)
const result = GetSubscriptionsResponseSchema.parse(await response.json())
result.data.forEach(app => {
console.log(`App: ${app.whatsapp_business_api_data.name}`)
})
import {
OverrideCallbackURLRequestSchema,
OverrideCallbackURLResponseSchema
} from 'whatsapp-cloud-api-types'
const requestBody = OverrideCallbackURLRequestSchema.parse({
override_callback_uri: 'https://your-webhook.com/endpoint',
verify_token: 'your-verify-token'
})
const response = await fetch(
`https://graph.facebook.com/v18.0/${wabaId}/subscribed_apps`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
}
)
const result = OverrideCallbackURLResponseSchema.parse(await response.json())
console.log('Override successful:', result.data[0].override_callback_uri)
import { UnsubscribeFromWABAResponseSchema } from 'whatsapp-cloud-api-types'
const response = await fetch(
`https://graph.facebook.com/v18.0/${wabaId}/subscribed_apps`,
{
method: 'DELETE',
headers: { Authorization: `Bearer ${accessToken}` }
}
)
const result = UnsubscribeFromWABAResponseSchema.parse(await response.json())
console.log('Unsubscribed:', result.success)
WhatsAppWebhookSchema - Validates any WhatsApp webhookMessagesWebhookSchema - Messages and status updatesMessageSchema - Individual message objectStatusSchema - Message status objectContactSchema - Contact informationMetadataSchema - Phone number metadataMessageTemplateStatusUpdateWebhookSchema - Template status changesMessageTemplateQualityUpdateWebhookSchema - Template quality changesMessageTemplateComponentsUpdateWebhookSchema - Template component updatesTemplateCategoryUpdateWebhookSchema - Template category changesSubscribeToWABAResponseSchema - Response from subscribe APIGetSubscriptionsResponseSchema - Response from get subscriptions APIUnsubscribeFromWABAResponseSchema - Response from unsubscribe APIOverrideCallbackURLRequestSchema - Request body for override callback URLOverrideCallbackURLResponseSchema - Response from override callback URL APIWhatsAppBusinessAPIDataSchema - App data objectSubscribedAppSchema - Subscribed app objectSubscribedAppWithOverrideSchema - Subscribed app with override URITemplateStatusEvent - Template status events (APPROVED, REJECTED, etc.)TemplateQualityScore - Quality scores (GREEN, YELLOW, RED, UNKNOWN)TemplateCategory - Template categories (AUTHENTICATION, MARKETING, UTILITY)TemplateButtonType - Button types (URL, PHONE_NUMBER, QUICK_REPLY, etc.)Contributions are welcome! Please read the contributing guidelines first.
# Install dependencies
bun install
# Run tests
bun test
# Run tests in watch mode
bun test:watch
# Build
bun run build
# Type check
bun run type-check
# Lint and format
bun run lint:fix
MIT © [Your Name]
All webhook types are validated against real examples from the WhatsApp Cloud API documentation:
# Run all tests including validation of 24 official webhook examples
bun test
The test suite validates every message type, status update, and error scenario to ensure 100% compatibility with the WhatsApp Cloud API.
This package provides two main features:
// Webhook handling
import { WhatsAppWebhookSchema, MessagesWebhookSchema } from 'whatsapp-cloud-api-types'
// API client
import { WhatsAppCloudAPI } from 'whatsapp-cloud-api-types'
// Individual schemas and types
import type { Message, Status, BusinessProfile } from 'whatsapp-cloud-api-types'
If you have any questions or issues, please open an issue on GitHub.
FAQs
All types of the WhatsApp Business cloud API in Zod
The npm package whatsapp-cloud-api-types receives a total of 121 weekly downloads. As such, whatsapp-cloud-api-types popularity was classified as not popular.
We found that whatsapp-cloud-api-types demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
PyPI adds Trusted Publishing support for GitLab Self-Managed as adoption reaches 25% of uploads

Research
/Security News
A malicious Chrome extension posing as an Ethereum wallet steals seed phrases by encoding them into Sui transactions, enabling full wallet takeover.

Security News
Socket is heading to London! Stop by our booth or schedule a meeting to see what we've been working on.