Skip to main content

TypeScript SDK

The official TypeScript SDK for ZapyAPI provides a type-safe, easy-to-use interface for interacting with your WhatsApp instances.

Installation

npm install @zapyapi/sdk
# or
yarn add @zapyapi/sdk
# or
pnpm add @zapyapi/sdk

Quick Start

import { ZapyClient } from '@zapyapi/sdk';

const client = new ZapyClient({
apiKey: 'your-api-key',
});

// Send a text message
const result = await client.messages.sendText('my-instance', {
to: '5511999999999',
message: 'Hello from ZapyAPI SDK!'
});

console.log('Message sent:', result.messageId);

Client Configuration

import { ZapyClient } from '@zapyapi/sdk';

const client = new ZapyClient({
// Required: Your API key from the dashboard
apiKey: 'your-api-key',

// Optional: Base URL (defaults to production)
baseUrl: 'https://api.zapyapi.com/api',

// Optional: Request timeout in milliseconds (default: 30000)
timeout: 30000,

// Optional: Custom headers
headers: {
'X-Custom-Header': 'value'
}
});

Available Resources

Instances

Manage your WhatsApp instances:

// List all instances
const { data: instances } = await client.instances.list();

// Get QR code for connecting
const qr = await client.instances.getQRCode('my-instance');
console.log('Scan this QR:', qr.qrCode);

// Restart an instance
await client.instances.restart('my-instance');

// Logout an instance
await client.instances.logout('my-instance');

// Check if numbers are on WhatsApp
const result = await client.instances.checkNumbers('my-instance', [
'5511999999999',
'5521888888888'
]);
for (const check of result.results) {
console.log(`${check.number}: ${check.exists ? 'On WhatsApp' : 'Not found'}`);
}

// Send typing indicator
await client.instances.sendPresence('my-instance', {
to: '5511999999999',
presence: 'composing'
});

// Get profile picture
const profile = await client.instances.getProfilePicture('my-instance', '5511999999999');
if (profile.url) {
console.log('Profile picture:', profile.url);
}

// Block/unblock contacts
await client.instances.blockContact('my-instance', '5511999999999');
await client.instances.unblockContact('my-instance', '5511999999999');

// Get group metadata
const group = await client.instances.getGroupMetadata('my-instance', '120363123456789012@g.us');
console.log(`Group: ${group.subject}, Participants: ${group.participants.length}`);

Messages

Send and manage messages:

// Send text message
await client.messages.sendText('my-instance', {
to: '5511999999999',
message: 'Hello!',
quoteMessageId: 'optional-message-id-to-reply'
});

// Send image
await client.messages.sendImage('my-instance', {
to: '5511999999999',
image: 'https://example.com/image.jpg', // URL or base64
caption: 'Check this out!',
viewOnce: false
});

// Send video
await client.messages.sendVideo('my-instance', {
to: '5511999999999',
video: 'https://example.com/video.mp4',
caption: 'Watch this video!'
});

// Send audio note (voice message)
await client.messages.sendAudioNote('my-instance', {
to: '5511999999999',
audio: 'data:audio/ogg;base64,...'
});

// Send audio file
await client.messages.sendAudioFile('my-instance', {
to: '5511999999999',
audio: 'https://example.com/audio.mp3'
});

// Send document
await client.messages.sendDocument('my-instance', {
to: '5511999999999',
document: 'https://example.com/file.pdf',
fileName: 'report.pdf',
caption: 'Here is the report'
});

// Forward a message
await client.messages.forward('my-instance', {
to: '5511999999999',
messageId: 'original-message-id'
});

// Edit a message
await client.messages.edit('my-instance', {
messageId: 'message-id',
message: 'Updated text'
});

// Mark as read
await client.messages.read('my-instance', {
messageId: 'message-id'
});

// Delete a message
await client.messages.delete('my-instance', {
messageId: 'message-id'
});

// Get media download link
const media = await client.messages.getMediaDownloadLink('my-instance', 'message-id');
console.log('Download URL:', media.url);

// Send location
await client.messages.sendLocation('my-instance', {
to: '5511999999999',
latitude: -23.5505,
longitude: -46.6333,
name: 'São Paulo',
address: 'São Paulo, Brazil'
});

// Send contact card
await client.messages.sendContact('my-instance', {
to: '5511999999999',
contact: {
fullName: 'John Doe',
phoneNumber: '+5511988887777',
organization: 'Acme Inc'
}
});

// Send sticker
await client.messages.sendSticker('my-instance', {
to: '5511999999999',
url: 'https://example.com/sticker.webp'
});

// Send reaction
await client.messages.sendReaction('my-instance', {
messageId: 'message-id',
reaction: '👍'
});

// Remove reaction
await client.messages.sendReaction('my-instance', {
messageId: 'message-id',
reaction: ''
});

Enums and Constants

The SDK exports type-safe enums and constants for common values:

import {
ZapyEventTypes,
InstanceStatus,
ZapyMessageStatusEnum,
ZapyMessageType,
WebhookQueueStatus
} from '@zapyapi/sdk';

// Check instance status
if (instance.status === InstanceStatus.CONNECTED) {
console.log('Ready to send messages!');
}

// Handle webhook events
if (payload.event === ZapyEventTypes.MESSAGE) {
console.log('New message received!');
}

// Check message delivery status
if (event.data.status === ZapyMessageStatusEnum.READ) {
console.log('Message was read!');
}

Available Enums

ZapyEventTypes

Event type constants for webhook handling:

ZapyEventTypes.MESSAGE           // 'message'
ZapyEventTypes.MESSAGE_STATUS // 'message-status'
ZapyEventTypes.REACTION // 'reaction'
ZapyEventTypes.PRESENCE // 'presence'
ZapyEventTypes.QR_CODE // 'qr-code'
ZapyEventTypes.CONTACT_CREATED // 'contact-created'
ZapyEventTypes.CONTACT_UPDATED // 'contact-updated'
ZapyEventTypes.CONTACT_DEDUPLICATED // 'contact-deduplicated'
ZapyEventTypes.INSTANCE_STATUS // 'instance-status'

InstanceStatus

InstanceStatus.STOPPED             // 'stopped'
InstanceStatus.MANUALLY_STOPPED // 'manually_stopped'
InstanceStatus.CONNECTING // 'connecting'
InstanceStatus.PENDING_QR_CODE_SCAN // 'pending_qr_code_scan'
InstanceStatus.CONNECTED // 'connected'
InstanceStatus.ERROR // 'error'
InstanceStatus.CREATED // 'created'
InstanceStatus.QR_TIMEOUT // 'qr_timeout'
InstanceStatus.PAYMENT_PENDING // 'payment_pending'

ZapyMessageStatusEnum

Message delivery status:

ZapyMessageStatusEnum.PENDING    // 'PENDING'
ZapyMessageStatusEnum.SENT // 'SENT'
ZapyMessageStatusEnum.RECEIVED // 'RECEIVED'
ZapyMessageStatusEnum.READ // 'READ'
ZapyMessageStatusEnum.PLAYED // 'PLAYED'
ZapyMessageStatusEnum.ERROR // 'ERROR'

ZapyMessageType

Message content types:

ZapyMessageType.TEXT           // 'text'
ZapyMessageType.IMAGE // 'image'
ZapyMessageType.VIDEO // 'video'
ZapyMessageType.AUDIO // 'audio'
ZapyMessageType.DOCUMENT // 'document'
ZapyMessageType.STICKER // 'sticker'
ZapyMessageType.LOCATION // 'location'
ZapyMessageType.LIVE_LOCATION // 'live_location'
ZapyMessageType.CONTACT // 'contact'
ZapyMessageType.REACTION // 'reaction'
ZapyMessageType.EDITED // 'edited'
ZapyMessageType.DELETED // 'deleted'
ZapyMessageType.POLL // 'poll'
ZapyMessageType.POLL_VOTE // 'poll_vote'
ZapyMessageType.CALL // 'call'

Webhook Handling

Type Guards

Use built-in type guards for type-safe webhook handling:

import {
ZapyWebhookPayload,
ZapyEventTypes,
ZapyMessageType,
isTextMessage,
isImageMessage,
isVideoMessage,
isAudioMessage,
isMediaMessage
} from '@zapyapi/sdk';

function handleWebhook(payload: ZapyWebhookPayload) {
switch (payload.event) {
case ZapyEventTypes.MESSAGE:
// Handle incoming message
const message = payload.data;
console.log('From:', message.sender.name);

// Use type guards to check message type
if (isTextMessage(message)) {
console.log('Text:', message.text);
} else if (isImageMessage(message)) {
console.log('Image caption:', message.caption);
} else if (isMediaMessage(message)) {
console.log('Media type:', message.messageType);
}
break;

case ZapyEventTypes.MESSAGE_STATUS:
// Handle message status update
console.log('Message ID:', payload.data.id);
console.log('Status:', payload.data.status);
break;

case ZapyEventTypes.QR_CODE:
// Handle QR code for authentication
console.log('QR Code:', payload.data.qr);
break;

case ZapyEventTypes.INSTANCE_STATUS:
// Handle instance status change
console.log('Instance:', payload.data.instanceId);
console.log('Status:', payload.data.status);
break;

case ZapyEventTypes.REACTION:
// Handle message reaction
console.log('Reaction:', payload.data.reaction);
console.log('Message ID:', payload.data.id);
break;

case ZapyEventTypes.PRESENCE:
// Handle presence update (typing, online, etc.)
console.log('Presence:', payload.data.presence);
console.log('Last seen:', payload.data.lastSeen);
break;

case ZapyEventTypes.CONTACT_CREATED:
case ZapyEventTypes.CONTACT_UPDATED:
// Handle contact events
console.log('Contact:', payload.data.contact.name);
break;
}
}

Signature Verification

Verify webhook signatures for security:

import { verifyWebhookSignature } from '@zapyapi/sdk';

app.post('/webhook', express.json(), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const isValid = verifyWebhookSignature(
req.body,
signature,
process.env.WEBHOOK_SECRET
);

if (!isValid) {
return res.status(401).send('Invalid signature');
}

// Process webhook...
res.status(200).send('OK');
});

Error Handling

The SDK provides typed errors for better error handling:

import {
ZapyClient,
ZapyApiError,
AuthenticationError,
RateLimitError,
InstanceNotFoundError,
ValidationError
} from '@zapyapi/sdk';

try {
await client.messages.sendText('my-instance', {
to: '5511999999999',
message: 'Hello!'
});
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof RateLimitError) {
console.error('Rate limit exceeded, retry after:', error.retryAfter);
} else if (error instanceof InstanceNotFoundError) {
console.error('Instance not found');
} else if (error instanceof ValidationError) {
console.error('Invalid request:', error.message);
} else if (error instanceof ZapyApiError) {
console.error('API error:', error.statusCode, error.message);
}
}

Utilities

The SDK includes helpful utility functions:

import {
normalizePhone,
isValidPhone,
isGroup,
extractPhone
} from '@zapyapi/sdk';

// Normalize phone number to WhatsApp format
normalizePhone('11999999999'); // '5511999999999'
normalizePhone('+55 11 99999-9999'); // '5511999999999'

// Validate phone number
isValidPhone('5511999999999'); // true
isValidPhone('invalid'); // false

// Check if ID is a group
isGroup('5511999999999@s.whatsapp.net'); // false
isGroup('123456789@g.us'); // true

// Extract phone from WhatsApp ID
extractPhone('5511999999999@s.whatsapp.net'); // '5511999999999'

TypeScript Support

The SDK is written in TypeScript and provides full type definitions:

import type {
// Common types
ZapyClientOptions,
PaginationQuery,
PaginatedResponse,

// Instance types
Instance,
CreateInstanceOptions,
QRCodeResponse,
CheckNumberResult,
CheckNumbersResponse,
PresenceType,
SendPresenceOptions,
ProfilePictureResponse,
GroupParticipant,
GroupMetadata,

// Message types (for sending)
SendTextMessageOptions,
SendImageMessageOptions,
SendVideoMessageOptions,
SendAudioNoteMessageOptions,
SendDocumentMessageOptions,
SendLocationMessageOptions,
SendContactMessageOptions,
ContactCardInfo,
SendStickerMessageOptions,
SendReactionOptions,
MessageResponse,

// Message event types (received via webhooks)
ZapyMessage,
ZapyTextMessage,
ZapyImageMessage,
ZapyVideoMessage,
ZapyAudioMessage,
ZapyDocumentMessage,
ZapyStickerMessage,
ZapyLocationMessage,
ZapyContactMessage,
ZapyReactionMessage,
ZapyPollMessage,
ZapyCallMessage,
ZapyChatInfo,
ZapySenderInfo,
ZapyMessageStatus,

// Webhook payload types
ZapyWebhookPayload,
ZapyEventMap,
ZapyEventType,
ZapyQRCodeEvent,
ZapyInstanceStatusEvent,
ZapyPresenceEvent,
ZapyReactionEvent,
ZapyContactCreatedEvent,
ZapyContactUpdatedEvent,
ZapyContactDeduplicatedEvent,
ZapyContact
} from '@zapyapi/sdk';

ESM and CommonJS

The SDK supports both ESM and CommonJS:

// ESM
import { ZapyClient } from '@zapyapi/sdk';

// CommonJS
const { ZapyClient } = require('@zapyapi/sdk');