Loading...

API Documentation

Complete guide for integrating with the Zapini API

Download Markdown

Base URL

https://instance-{id}.zapini.app

Authentication

Bearer Token (Sanctum)

Rate Limit

100 requests / 15 min

Getting Started

The Zapini REST API allows you to integrate WhatsApp messaging capabilities into your applications. All requests must use HTTPS and include Bearer token authentication.

API Types

Zapini offers two types of APIs for different needs. Choose the one that best fits your use case.

Universal API

https://zapini.app/api/v1

Complete REST API to manage all your instances, conversations, contacts, and settings. Use this API for web/mobile applications that need full system access.

Manage multiple instances Conversations and contacts Tags and automations Statistics and reports

Instance API

https://instance-{id}.zapini.app/

Direct API for sending messages with low latency. Each WhatsApp instance has its own dedicated URL. Ideal for bots and high-volume automations.

Send messages (text media) Connection status QR Code for connection Real-time webhooks

Which API should I use?

Use Case Recommended API
Web/mobile application Universal (Sanctum Token)
Message bot Instance (sk_ Token)
CRM / Support system Universal (Sanctum Token)
Bulk messaging / campaigns Instance (sk_ Token)
Simple external integration Instance (sk_ Token)

Instance ID

The API accepts both numeric ID and UUID in all endpoints.

Numeric ID UUID
Example 777 550e8400-e29b-...
Where to find Shown on the instance card. Example: 777 Shown on the instance details page. Example: 550e8400-e29b-41d4-a716-446655440000

With an sk_ token, the instance_id parameter is optional — it is automatically detected from the token.

Required Headers

Authorization: Bearer {token}
Accept: application/json
Content-Type: application/json

Response Format

Success Response

{
  "success": true,
  "message": "Operation completed",
  "data": { ... }
}

Error Response

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Error description",
    "details": {}
  }
}

HTTP Status Codes

Code Description
200OK - Successful request
201Created - Resource created successfully
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing token
403Forbidden - No permission for this resource
404Not Found - Resource not found
422Unprocessable Entity - Validation error
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server error

Authentication

Token Types

There are two types of authentication tokens, each suited for different scenarios.

Sanctum Token

User token obtained via login. Gives access to all instances and resources in your tenant. Ideal for web/mobile applications where the user logs in.

  • • How to get: POST /auth/login with email and password
  • • Format: 1|abc123xyz...
  • • Access: All tenant instances

Instance Token (sk_)

Token specific to a WhatsApp instance. Generated in the admin panel. Ideal for external integrations and bots.

  • • How to get: Generate in panel at Instances > API Tokens
  • • Format: sk_xxxxxxxxxxxxxxxx
  • • Access: Only the specific instance

Both tokens work the same way in the Authorization header:

Authorization: Bearer {token}
POST /auth/login

Authenticates a user and returns an access token.

Parameters

Field Type Required Description
email string Yes User email
password string Yes User password
device_name string No Device name for token identification

Example

curl -X POST https://instance-{id}.zapini.app/auth/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "your_password",
    "device_name": "My App"
  }'

Response

{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": {
      "id": 1,
      "name": "User Name",
      "email": "user@example.com",
      "role": "admin"
    },
    "token": "1|abc123xyz...",
    "token_type": "Bearer"
  }
}
GET /auth/me

Returns information about the authenticated user.

Example

curl -X GET https://instance-{id}.zapini.app/auth/me \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
POST /auth/logout

Revokes the current access token.

Example

curl -X POST https://instance-{id}.zapini.app/auth/logout \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
POST /auth/refresh

Refreshes the access token.

Example

curl -X POST https://instance-{id}.zapini.app/auth/refresh \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Instances

GET /instances

Lists all WhatsApp instances in your account.

Query Parameters

Field Type Description
status string connected, disconnected, qr_ready, pending

Example

curl -X GET "https://instance-{id}.zapini.app/instances?status=connected" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "data": {
    "instances": [
      {
        "uuid": "550e8400-e29b-41d4-a716-446655440000",
        "phone_number": "5511999999999",
        "status": "connected",
        "connected": true,
        "messages_sent_today": 50,
        "remaining_quota": 450,
        "can_send_messages": true,
        "last_activity_at": "2025-01-15T10:30:00Z"
      }
    ]
  }
}
GET /instances/{id}

Returns details of a specific instance.

The API accepts both numeric ID and UUID in all endpoints.

Example

# Numeric IDcurl -X GET https://instance-{id}.zapini.app/instances/777 \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

# UUID
curl -X GET https://instance-{id}.zapini.app/instances/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
GET /instances/{id}/qr

Returns the QR code to connect the instance.

Example

curl -X GET https://instance-{id}.zapini.app/instances/777/qr \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "data": {
    "status": "qr_ready",
    "qr_code": "data:image/png;base64,...",
    "qr_code_text": "2@...",
    "qr_generated_at": "2025-01-15T10:30:00Z",
    "qr_expired": false,
    "message": "QR code ready to scan"
  }
}
GET /instances/{id}/status

Returns the current status of the instance.

Query Parameters

Field Type Description
realtime boolean If true, checks status in real-time on the server

Example

curl -X GET "https://instance-{id}.zapini.app/instances/777/status?realtime=true" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
GET /instances/{id}/stats

Returns usage statistics for the instance.

Response

{
  "success": true,
  "data": {
    "messages_sent_today": 50,
    "remaining_quota": 450,
    "daily_limit": 500,
    "messages_this_week": 200,
    "messages_this_month": 800,
    "messages_received_today": 30,
    "conversations_count": 150,
    "contacts_count": 500
  }
}
POST /instances/{id}/disconnect

Disconnects the WhatsApp instance.

Example

curl -X POST https://instance-{id}.zapini.app/instances/777/disconnect \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
POST /instances/{id}/reconnect

Initiates the instance reconnection process.

Example

curl -X POST https://instance-{id}.zapini.app/instances/777/reconnect \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Messages

Instance API

Direct API for sending messages with low latency. Each WhatsApp instance has its own dedicated URL. Ideal for bots and high-volume automations.

Base URL:

https://instance-{id}.zapini.app
Instance Token (sk_) Required

Universal API - /chat/send

Para enviar mensagens via API Universal, use o endpoint /chat/send (consulte a aba Chat API).

POST /send-message

Sends a text message to a WhatsApp number.

Parameters

Field Type Required Description
recipient (ou number, to) string Yes Recipient WhatsApp number (with country code) (5511999999999)
message string Yes Text message content
reply_to (ou quoted_message_id) string No Message ID to reply to
Alternative parameters: Os campos recipient, number e to são equivalentes. Assim como reply_to e quoted_message_id.

Example

curl -X POST https://instance-{id}.zapini.app/send-message \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "5511999999999",
    "message": "Olá! Esta é uma mensagem de teste."
  }'

Response

{
  "success": true,
  "message": "Message sent successfully",
  "message_id": "3EB0B430A8B7F23C1D12",
  "timestamp": "2025-12-30T17:30:00.000Z"
}
POST /send-media

Sends a message with media (image, video, audio, document).

Parameters

Field Type Required Description
recipient (ou number, to) string Yes Recipient WhatsApp number (with country code) (5511999999999)
media_url (ou url) string Yes Public URL of the media file
media_type (ou type) string Yes image, video, audio, document
caption string No Caption for images and videos
filename string No Filename for documents
Alternative parameters: Os campos recipient/number/to, media_url/url e media_type/type são equivalentes.

Example

curl -X POST https://instance-{id}.zapini.app/send-media \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "5511999999999",
    "media_url": "https://example.com/image.jpg",
    "media_type": "image",
    "caption": "Confira esta imagem!"
  }'

Response

{
  "success": true,
  "message": "Media sent successfully",
  "message_id": "3EB0B430A8B7F23C1D13",
  "timestamp": "2025-12-30T17:30:00.000Z"
}
POST /send-reaction

Sends a reaction emoji to a specific message.

Parameters

Field Type Required Description
to string Yes JID do chat
messageId string Yes ID da mensagem para reagir
emoji string Yes Emoji da reação (ex: 👍, ❤️, 😂)

Example

curl -X POST https://instance-{id}.zapini.app/send-reaction \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "5511999999999@s.whatsapp.net",
    "messageId": "3EB0B430A8B7F23C1D12",
    "emoji": "👍"
  }'
GET /status

Returns the current connection status of the WhatsApp instance.

Example

curl -X GET https://instance-{id}.zapini.app/status \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "status": "connected",
  "phone": "5511999999999",
  "name": "Meu WhatsApp",
  "platform": "android"
}
GET /qr

Returns the QR code to connect the WhatsApp instance. Only available when status is qr_ready.

Example

curl -X GET https://instance-{id}.zapini.app/qr \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "qr": "data:image/png;base64,iVBORw0KGgoAAAA...",
  "status": "qr_ready"
}
GET /health

Returns the health status of the API server. No authentication required.

Example

curl -X GET https://instance-{id}.zapini.app/health

Response

{
  "status": "ok",
  "uptime": 123456,
  "timestamp": "2025-12-15T14:30:00.000Z"
}

Conversations

GET /conversations

Lists all active conversations.

Query Parameters

Field Type Description
instance_id string Filter by instance (UUID)
unread boolean Show only unread conversations
search string Search by name or number
is_group boolean Filter by groups (true/false)
per_page integer Items per page (max 100)
include_tags boolean Include conversation tags in response
tag_id uuid Filter by tag ID
tag_ids uuid[] Filter by multiple tag UUIDs (comma-separated or array)
untagged boolean Only show conversations without tags
format string Use chat-optimized response format (chat)

?format=chat: The Chat API returns the same data as standard endpoints but with additional fields optimized for UI rendering. You can also use ?format=chat on standard endpoints.

Example

curl -X GET "https://instance-{id}.zapini.app/conversations?unread=true&per_page=20" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440045",
      "contact_number": "5511999999999",
      "contact_name": "John Doe",
      "display_name": "John Doe",
      "is_group": false,
      "profile_picture_url": "https://...",
      "last_message": "Ok, deal!",
      "last_message_at": "2025-01-15T10:30:00Z",
      "unread_count": 2,
      "is_archived": false
    }
  ],
  "meta": {
    "pagination": {
      "total": 100,
      "per_page": 20,
      "current_page": 1,
      "last_page": 5
    }
  }
}
GET /conversations/{uuid}

Returns details of a specific conversation.

GET /conversations/{uuid}/messages

Returns message history for a conversation.

Query Parameters

Field Type Description
from datetime Start date (ISO 8601)
to datetime End date (ISO 8601)
before_id integer Messages before this ID
after_id integer Messages after this ID
limit integer Message limit (max 100)
format string Use chat-optimized response format (chat)

?format=chat: Returns messages with formatted_body (resolved @mentions) and grouped reactions.

POST /conversations/{uuid}/mark-read

Marks a conversation as read.

POST /conversations/{uuid}/archive

Archives a conversation.

Response

{
  "success": true,
  "message": "Conversation archived.",
  "data": {
    "archived_id": "550e8400-e29b-41d4-a716-446655440045",
    "archived_at": "2025-12-29T12:00:00.000000Z"
  }
}
DELETE /conversations/{uuid}/archive

Restores an archived conversation back to active status.

The UUID must be from an archived conversation. Use GET /conversations/archived to list archived conversations.

Response

{
  "success": true,
  "message": "Conversation restored.",
  "data": {
    "conversation_id": "550e8400-e29b-41d4-a716-446655440045",
    "restored": true
  }
}
DELETE /conversations/{uuid}

Deletes a conversation and its messages.

Automation Control

Manage AI automation for conversations. When automation is active, manual messages are blocked until you take over the chat.

Important: Automation Behavior

  • When automation is active, manual messages are blocked to prevent conflicts with AI responses.
  • Use "pause" to take over the chat and send messages manually.
  • Use "resume" to let the AI handle the conversation again.
  • IMPORTANT: To resume automation, you must first archive the conversation.

Security: Archive Required to Resume

Automation can only be resumed after archiving the conversation. This ensures the manual service session is properly closed before returning control to AI. When resuming, the conversation will be automatically unarchived.

GET /conversations/{uuid}/automation

Returns the current automation status for a conversation.

Response

{
  "success": true,
  "data": {
    "conversation_id": "550e8400-e29b-41d4-a716-446655440045",
    "automation_status": "active",
    "is_automation_active": true,
    "can_send_manual_message": false,
    "paused_at": null,
    "paused_by": null,
    "pause_reason": null
  }
}
POST /conversations/{uuid}/automation/pause

Pauses automation for a conversation, allowing manual messages.

Request Body

Field Type Required Description
reason string No Optional reason for pausing automation

Example

curl -X POST "https://instance-{id}.zapini.app/conversations/550e8400-e29b-41d4-a716-446655440045/automation/pause" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Manual takeover for VIP client"}'

Response

{
  "success": true,
  "message": "Automation paused. You can now send messages manually.",
  "data": {
    "automation_status": "paused",
    "paused_at": "2025-12-20T14:30:00Z",
    "paused_by": "John Doe"
  }
}
POST /conversations/{uuid}/automation/resume

Resumes automation for a conversation, letting AI handle responses.

Response

{
  "success": true,
  "message": "Automation resumed. AI will handle this conversation.",
  "data": {
    "automation_status": "active"
  }
}
POST /conversations/automation/bulk-pause

Pauses automation for multiple conversations at once.

Request Body

Field Type Required Description
conversation_ids array Yes Array of conversation IDs to process
reason string No Optional reason for pausing automation

Example

curl -X POST "https://instance-{id}.zapini.app/conversations/automation/bulk-pause" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"conversation_ids": ["550e8400-e29b-41d4-a716-446655440001", "550e8400-e29b-41d4-a716-446655440002", "550e8400-e29b-41d4-a716-446655440003"]}'

Response

{
  "success": true,
  "message": "3 conversations paused successfully."
}
POST /conversations/automation/bulk-resume

Resumes automation for multiple conversations at once.

Request Body

Field Type Required Description
conversation_ids array Yes Array of conversation IDs to process

Response

{
  "success": true,
  "message": "3 conversations resumed successfully."
}

Contacts

GET /contacts

Lists all saved contacts.

Query Parameters

Field Type Description
instance_id string Filter by instance (UUID)
search string Search by name or number
per_page integer Items per page (max 100)

Example

curl -X GET "https://instance-{id}.zapini.app/contacts?search=john&per_page=50" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "phone_number": "5511999999999",
      "name": "John Doe",
      "display_name": "John",
      "email": "john@example.com",
      "company": "Acme Inc",
      "notes": "VIP customer",
      "profile_picture_url": "https://...",
      "is_business": false,
      "created_at": "2025-01-15T10:30:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "total": 500,
      "per_page": 50,
      "current_page": 1,
      "last_page": 10
    }
  }
}
POST /contacts

Creates a new contact.

Parameters

Field Type Required Description
instance_id string Yes ID da instância
phone_number string Yes Contact phone number
name string No Contact name
email string No Contact email
company string No Contact company
notes string No Notes about the contact

Example

curl -X POST https://instance-{id}.zapini.app/contacts \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "550e8400-e29b-41d4-a716-446655440000",
    "phone_number": "+5511999999999",
    "name": "John Doe",
    "email": "john@example.com",
    "company": "Acme Inc",
    "notes": "Met at conference"
  }'
GET /contacts/{id}

Returns details of a specific contact.

PUT /contacts/{id}

Updates an existing contact.

Parameters

Field Type Description
name string Contact name
email string Contact email
company string Contact company
notes string Notes about the contact
DELETE /contacts/{id}

Deletes a contact.

POST /contacts/import

Imports multiple contacts at once.

Parameters

Field Type Required Description
instance_id string Yes ID da instância
contacts array Yes Array of contact objects

Example

curl -X POST https://instance-{id}.zapini.app/contacts/import \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "550e8400-e29b-41d4-a716-446655440000",
    "contacts": [
      {"phone_number": "+5511999999999", "name": "John Doe"},
      {"phone_number": "+5511888888888", "name": "Jane Smith"}
    ]
  }'

Response

{
  "success": true,
  "message": "Contacts imported successfully",
  "data": {
    "imported": 2,
    "skipped": 0,
    "errors": []
  }
}
GET /contacts/export

Exports contacts in JSON or CSV format.

Query Parameters

Field Type Description
instance_id string Filter by instance (UUID)
format string json, csv (default: json)

Example

curl -X GET "https://instance-{id}.zapini.app/contacts/export?format=csv" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Webhooks

Webhook System

Webhooks allow you to receive real-time notifications about events in your WhatsApp instances.

Incoming Webhooks

URLs that Zapini uses to receive data from your WhatsApp instances.

Outgoing Webhooks

URLs you configure to receive notifications from Zapini.

Outgoing Webhooks

Receive real-time notifications on your server

NEW

Configure webhooks to receive real-time notifications when events occur in your WhatsApp instance. Zapini will send HTTP POST requests to your configured URL with event data.

How to Configure

  1. Go to your API Token settings and click "Configure Webhook"
  2. Enter your webhook URL (must be HTTPS in production)
  3. Generate or enter a secret key for signature verification
  4. Select which events you want to receive and save

Available Events

Event Description
message.received New message received
message.sent Message sent
message.status Message status changed (sent, delivered, read)
instance.connected Instance connected to WhatsApp
instance.disconnected Instance disconnected
instance.qr New QR code generated

Understanding Message IDs

Each message has two identifiers. Use the correct one depending on your use case:

Field Format Usage
message_id UUID (e.g., 055f01b2-da7b-476b-...) Primary key for deduplication and tracking in your system
whatsapp_message_id WhatsApp ID (e.g., 3EB0ABC123456789) Required for reactions, replies, and WhatsApp operations

Tip: How to prevent duplicates

Store message_id when you receive a webhook. Before processing new webhooks, check if message_id already exists in your database. If it does, update the existing record instead of creating a new one.

Request Format

Each webhook request is sent as an HTTP POST with the following headers:

POST https://your-server.com/webhook
Content-Type: application/json
X-Webhook-Signature: a1b2c3d4e5f6...
X-Webhook-Event: message.received
X-Instance-UUID: 550e8400-e29b-41d4-a716-446655440000
User-Agent: Zapini-Webhook/1.0

Webhook Headers

Header Description
X-Webhook-Signature HMAC-SHA256 signature of the JSON payload using your secret key
X-Webhook-Event The event type that triggered this webhook
X-Instance-UUID UUID of the WhatsApp instance
User-Agent Zapini-Webhook/1.0

Payload Examples

message.received

{
  "event": "message.received",
  "instance_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2025-01-15T10:30:00+00:00",
  "data": {
    "message_id": "055f01b2-da7b-476b-9a5d-dcecb3fe510c",
    "whatsapp_message_id": "3EB0ABC123456789",
    "sender_number": "5511999999999",
    "sender_name": "John Doe",
    "content": "Hello, I need help!",
    "media_type": null,
    "media_url": null,
    "timestamp": "2025-01-15T10:30:00+00:00",
    "conversation_id": 123
  }
}

message.sent

{
  "event": "message.sent",
  "instance_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2025-01-15T10:31:00+00:00",
  "data": {
    "message_id": "f4a2e8c9-7b3d-4e5f-8a1c-2d9e6f0a3b7c",
    "whatsapp_message_id": "3EB0ABC123456789",
    "recipient_number": "5511888888888",
    "content": "Thanks for contacting us!",
    "media_type": null,
    "media_url": null,
    "timestamp": "2025-01-15T10:31:00+00:00",
    "conversation_id": 123
  }
}

message.status

{
  "event": "message.status",
  "instance_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2025-01-15T10:32:00+00:00",
  "data": {
    "message_id": "f4a2e8c9-7b3d-4e5f-8a1c-2d9e6f0a3b7c",
    "whatsapp_message_id": "3EB0ABC123456789",
    "previous_status": "sent",
    "new_status": "delivered",
    "recipient_number": "5511888888888",
    "timestamp": "2025-01-15T10:32:00+00:00"
  }
}

instance.connected

{
  "event": "instance.connected",
  "instance_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2025-01-15T10:00:00+00:00",
  "data": {
    "previous_status": "qr_ready",
    "new_status": "connected",
    "phone_number": "5511999999999"
  }
}
POST /webhooks/instance/{uuid}/incoming

Receives incoming messages from WhatsApp instances.

Payload Format

{
  "remoteJid": "5511999999999@s.whatsapp.net",
  "message": {
    "conversation": "Hello, how are you?",
    "extendedTextMessage": null,
    "imageMessage": null,
    "videoMessage": null,
    "audioMessage": null,
    "documentMessage": null
  },
  "messageTimestamp": 1705312200,
  "pushName": "John Doe",
  "key": {
    "remoteJid": "5511999999999@s.whatsapp.net",
    "fromMe": false,
    "id": "3EB0ABC123456789"
  },
  "participant": null,
  "isGroup": false
}

Message Types

Type Field Description
Text message.conversation Simple text message
Extended Text message.extendedTextMessage Text with link preview
Image message.imageMessage Image with caption
Video message.videoMessage Video message
Audio message.audioMessage Audio/voice message
Document message.documentMessage Document/file

Example - Text Message

curl -X POST https://zapini.app/webhooks/instance/{uuid}/incoming \
  -H "Content-Type: application/json" \
  -d '{
    "remoteJid": "5511999999999@s.whatsapp.net",
    "message": {
      "conversation": "Hello!"
    },
    "messageTimestamp": 1705312200,
    "pushName": "Customer Name",
    "key": {
      "remoteJid": "5511999999999@s.whatsapp.net",
      "fromMe": false,
      "id": "ABC123"
    }
  }'
POST /webhooks/instance/{uuid}/status

Receives status updates for sent messages.

Payload Format

{
  "key": {
    "remoteJid": "5511999999999@s.whatsapp.net",
    "id": "3EB0ABC123456789",
    "fromMe": true
  },
  "status": 3,
  "messageTimestamp": 1705312200
}

Status Codes

Code Status Description
1 pending Message pending to be sent
2 sent Message sent to server
3 delivered Message delivered to recipient
4 read Message read by recipient
5 played Audio/video played
POST /webhooks/instance/{uuid}/qr

Receives QR code updates for connection.

Payload Format

{
  "qr": "2@ABC123...",
  "qr_image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
  "generated_at": "2025-01-15T10:30:00Z"
}
POST /webhooks/instance/{uuid}/connection

Receives instance connection status updates.

Payload Format

{
  "status": "connected",
  "phone_number": "5511999999999",
  "timestamp": "2025-01-15T10:30:00Z"
}

Connection Statuses

Status Description
connected Instance connected and working
qr_ready QR code ready to scan
disconnected Instance disconnected
offline Instance offline
POST /webhooks/instance/{uuid}/reaction

Receives emoji reactions on messages.

Payload Format

{
  "key": {
    "remoteJid": "5511999999999@s.whatsapp.net",
    "id": "3EB0ABC123456789",
    "fromMe": false
  },
  "reaction": {
    "text": "👍",
    "key": {
      "id": "3EB0DEF987654321"
    }
  },
  "senderJid": "5511888888888@s.whatsapp.net"
}
PUT /instances/{uuid}/webhook

Configure an external URL to receive event notifications.

Parameters

Field Type Required Description
webhook_url string Yes URL that will receive notifications via POST
webhook_secret string No Secret key for request signing
events array No Events that will trigger the webhook
is_active boolean No Enable or disable the webhook

Available Events

message.incoming message.outgoing message.status message.reaction message.deleted connection.update qr.update contact.update

Example

curl -X PUT https://instance-{id}.zapini.app/instances/550e8400-e29b-41d4-a716-446655440000/webhook \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-server.com/webhook",
    "webhook_secret": "your_secret_key_here",
    "events": ["message.incoming", "message.status"],
    "is_active": true
  }'

Webhook Security

All webhook requests include an HMAC signature for authenticity verification.

Signature Verification

Each request includes an X-Webhook-Signature header with the HMAC-SHA256 signature of the payload.

Header:

X-Webhook-Signature: a1b2c3d4e5f6789...

Verify Signature (PHP)

<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = 'your_webhook_secret';

$expected = hash_hmac('sha256', $payload, $secret);

if (hash_equals($expected, $signature)) {
    // Signature is valid
    $data = json_decode($payload, true);
    // Process webhook...
} else {
    http_response_code(401);
    exit('Invalid signature');
}

Verify Signature (Node.js)

const crypto = require('crypto');

app.post('/webhook', (req, res) => {
    const signature = req.headers['x-webhook-signature'];
    const secret = 'your_webhook_secret';
    const payload = JSON.stringify(req.body);

    const expected = crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('hex');

    if (crypto.timingSafeEqual(
        Buffer.from(signature),
        Buffer.from(expected)
    )) {
        // Signature is valid
        console.log('Webhook received:', req.body);
        res.status(200).send('OK');
    } else {
        res.status(401).send('Invalid signature');
    }
});

Best Practices

  • Always verify the signature before processing the webhook.
  • Respond quickly (within 5 seconds) to avoid timeouts.
  • Use a queue to process webhooks asynchronously.
  • Implement idempotency to handle duplicate webhooks.
  • Log all received webhooks for debugging.

Media

Media Management

Send and manage media files such as images, videos, audio, and documents.

📷
Images
jpg, png, gif, webp
🎥
Videos
mp4, 3gp, mov
🎵
Audio
mp3, ogg, wav, opus
📄
Documents
pdf, doc, xls, etc
POST /media/upload

Uploads a media file for later use.

Parameters

Field Type Required Description
file file Yes Media file for upload (multipart/form-data)
type string No image, video, audio, document (auto-detected)

Example

curl -X POST https://instance-{id}.zapini.app/media/upload \
  -H "Authorization: Bearer {token}" \
  -F "file=@/path/to/image.jpg" \
  -F "type=image"

Response

{
  "success": true,
  "data": {
    "id": "media_abc123xyz",
    "url": "https://storage.zapini.app/media/abc123xyz.jpg",
    "type": "image",
    "mime_type": "image/jpeg",
    "size": 102400,
    "filename": "image.jpg",
    "expires_at": "2025-01-22T10:30:00Z"
  }
}
GET /media/{id}

Returns information about a media file.

Response

{
  "success": true,
  "data": {
    "id": "media_abc123xyz",
    "url": "https://storage.zapini.app/media/abc123xyz.jpg",
    "type": "image",
    "mime_type": "image/jpeg",
    "size": 102400,
    "filename": "image.jpg",
    "created_at": "2025-01-15T10:30:00Z",
    "expires_at": "2025-01-22T10:30:00Z"
  }
}
DELETE /media/{id}

Deletes a media file.

Example

curl -X DELETE https://instance-{id}.zapini.app/media/media_abc123xyz \
  -H "Authorization: Bearer {token}"
POST /messages/send-media

Sends a message with attached media.

Parameters

Field Type Required Description
instance_id string Yes ID da instância
recipient string Yes Recipient WhatsApp number (with country code)
media_url string Yes* Public URL of the media file
media_id string Yes* ID of a previously uploaded media
media_type string Yes image, video, audio, document
caption string No Caption for images and videos
filename string No Filename for documents

* Provide media_url OR media_id

Example - Image

curl -X POST https://instance-{id}.zapini.app/messages/send-media \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "550e8400-e29b-41d4-a716-446655440000",
    "recipient": "+5511999999999",
    "media_url": "https://example.com/image.jpg",
    "media_type": "image",
    "caption": "Check this image!"
  }'

Example - Document

curl -X POST https://instance-{id}.zapini.app/messages/send-media \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "550e8400-e29b-41d4-a716-446655440000",
    "recipient": "+5511999999999",
    "media_url": "https://example.com/report.pdf",
    "media_type": "document",
    "filename": "Monthly_Report.pdf",
    "caption": "Here is the monthly report"
  }'

Media Limits

Type Max Size Formats
Images 16 MB jpg, jpeg, png, gif, webp
Videos 64 MB mp4, 3gp, mov, avi, mkv
Audio 16 MB mp3, ogg, wav, opus, aac, m4a
Documents 100 MB pdf, doc, docx, xls, xlsx, ppt, pptx, txt, zip
GET /messages/{uuid}/media

Downloads media received in a message.

Example

curl -X GET https://instance-{id}.zapini.app/messages/660e8400-e29b-41d4-a716-446655440001/media \
  -H "Authorization: Bearer {token}" \
  --output downloaded_media.jpg

Response

Returns the binary file with the appropriate Content-Type.

Groups

Manage WhatsApp groups through the API. Create groups, add/remove participants, update settings, and more.

GET /instances/{uuid}/groups

Returns all WhatsApp groups from the instance.

Example

curl -X GET "https://instance-{id}.zapini.app/instances/{uuid}/groups" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "data": {
    "groups": [
      {
        "jid": "120363001234567890@g.us",
        "subject": "Marketing Team",
        "owner": "5511987654321@s.whatsapp.net",
        "size": 25,
        "description": "Team discussions"
      }
    ],
    "total": 5
  }
}
POST /instances/{uuid}/groups

Creates a new WhatsApp group.

Request Body

Field Type Required Description
subject string Yes api-docs.group_subject_desc
participants array Yes api-docs.group_participants_desc

Example

curl -X POST "https://instance-{id}.zapini.app/instances/{uuid}/groups" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "My New Group",
    "participants": ["5511987654321", "5511976543210"]
  }'

Response

{
  "success": true,
  "data": {
    "group": {
      "jid": "120363001234567890@g.us",
      "subject": "My New Group"
    },
    "message": "Group created successfully"
  }
}
GET /instances/{uuid}/groups/{jid}

Returns detailed metadata of a specific group.

Response

{
  "success": true,
  "data": {
    "jid": "120363001234567890@g.us",
    "subject": "Marketing Team",
    "description": "Team discussions",
    "owner": "5511987654321@s.whatsapp.net",
    "participants": [
      {"jid": "5511987654321@s.whatsapp.net", "admin": "superadmin"},
      {"jid": "5511976543210@s.whatsapp.net", "admin": null}
    ],
    "size": 25
  }
}
PATCH /instances/{uuid}/groups/{jid}

Updates the group name and/or description.

Request Body

Field Type Description
subject string New group name
description string New group description

Example

curl -X PATCH "https://instance-{id}.zapini.app/instances/{uuid}/groups/{jid}" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "New Group Name",
    "description": "Updated description"
  }'
POST /instances/{uuid}/groups/{jid}/participants

Adds one or more participants to the group.

Example

curl -X POST "https://instance-{id}.zapini.app/instances/{uuid}/groups/{jid}/participants" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "participants": ["5511987654321", "5511976543210"]
  }'
DELETE /instances/{uuid}/groups/{jid}/participants

Removes one or more participants from the group.

Example

curl -X DELETE "https://instance-{id}.zapini.app/instances/{uuid}/groups/{jid}/participants" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "participants": ["5511987654321"]
  }'
POST /instances/{uuid}/groups/{jid}/admins

api-docs.groups_promote_desc

Example

curl -X POST "https://instance-{id}.zapini.app/instances/{uuid}/groups/{jid}/admins" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "participants": ["5511987654321"]
  }'
DELETE /instances/{uuid}/groups/{jid}/admins

api-docs.groups_demote_desc

Example

curl -X DELETE "https://instance-{id}.zapini.app/instances/{uuid}/groups/{jid}/admins" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "participants": ["5511987654321"]
  }'
POST /instances/{uuid}/groups/{jid}/leave

Makes the instance leave a group.

Example

curl -X POST "https://instance-{id}.zapini.app/instances/{uuid}/groups/{jid}/leave" \
  -H "Authorization: Bearer {token}"
GET /instances/{uuid}/groups/{jid}/invite

api-docs.groups_invite_get_desc

Response

{
  "success": true,
  "data": {
    "code": "AbCdEfGhIjKl",
    "invite_link": "https://chat.whatsapp.com/AbCdEfGhIjKl"
  }
}
DELETE /instances/{uuid}/groups/{jid}/invite

api-docs.groups_invite_revoke_desc

Response

{
  "success": true,
  "data": {
    "new_code": "MnOpQrStUvWx",
    "new_invite_link": "https://chat.whatsapp.com/MnOpQrStUvWx"
  },
  "message": "Invite link revoked"
}

Tags

Manage conversation tags for organizing and categorizing chats. Tags are tenant-scoped and can be assigned to multiple conversations.

GET /tags

Lists all tags for the current tenant.

Example

curl -X GET "https://instance-{id}.zapini.app/tags" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "data": {
    "tags": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "VIP",
        "color": "#f59e0b",
        "conversations_count": 15,
        "created_at": "2025-01-15T10:30:00Z",
        "updated_at": "2025-01-15T10:30:00Z"
      },
      {
        "id": "550e8400-e29b-41d4-a716-446655440002",
        "name": "Support",
        "color": "#3b82f6",
        "conversations_count": 42,
        "created_at": "2025-01-15T10:35:00Z",
        "updated_at": "2025-01-15T10:35:00Z"
      }
    ]
  }
}
POST /tags

Creates a new tag.

Request Body

Field Type Required Description
name string Yes Tag name (unique per tenant) (max 50)
color string Yes Hex color code for the tag (#RRGGBB)

Example

curl -X POST "https://instance-{id}.zapini.app/tags" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Important",
    "color": "#ef4444"
  }'

Response

{
  "success": true,
  "message": "Tag created successfully",
  "data": {
    "tag": {
      "id": "550e8400-e29b-41d4-a716-446655440003",
      "name": "Important",
      "color": "#ef4444",
      "conversations_count": 0,
      "created_at": "2025-01-15T12:00:00Z",
      "updated_at": "2025-01-15T12:00:00Z"
    }
  }
}
GET /tags/{uuid}

Returns details of a specific tag.

Example

curl -X GET "https://instance-{id}.zapini.app/tags/550e8400-e29b-41d4-a716-446655440001" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
PATCH /tags/{uuid}

Updates an existing tag.

Request Body

Field Type Required Description
name string No Tag name (unique per tenant) (max 50)
color string No Hex color code for the tag (#RRGGBB)

Example

curl -X PATCH "https://instance-{id}.zapini.app/tags/550e8400-e29b-41d4-a716-446655440001" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Very Important",
    "color": "#dc2626"
  }'
DELETE /tags/{uuid}

Deletes a tag. The tag will be automatically removed from all conversations.

Example

curl -X DELETE "https://instance-{id}.zapini.app/tags/550e8400-e29b-41d4-a716-446655440001" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"

Response

{
  "success": true,
  "message": "Tag deleted successfully"
}
PUT /conversations/{uuid}/tags

Updates the tags assigned to a conversation. This replaces all existing tags with the provided list.

Request Body

Field Type Required Description
tag_ids array Yes Array of tag UUIDs to assign to the conversation

Example

curl -X PUT "https://instance-{id}.zapini.app/conversations/550e8400-e29b-41d4-a716-446655440000/tags" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "tag_ids": ["550e8400-e29b-41d4-a716-446655440001", "550e8400-e29b-41d4-a716-446655440002"]
  }'

Response

{
  "success": true,
  "message": "Conversation tags updated",
  "data": {
    "tags": [
      {"id": "550e8400-e29b-41d4-a716-446655440001", "name": "VIP", "color": "#f59e0b"},
      {"id": "550e8400-e29b-41d4-a716-446655440002", "name": "Support", "color": "#3b82f6"},
      {"id": "550e8400-e29b-41d4-a716-446655440003", "name": "Important", "color": "#ef4444"}
    ]
  }
}

To remove all tags from a conversation, send an empty array: {"tag_ids": []}

Chat API

UI-OPTIMIZED

Endpoints optimized for building WhatsApp-like chat interfaces. Returns pre-formatted data with resolved @mentions, grouped reactions, and alignment helpers.

formatted_body

Pre-resolved @mentions in HTML format

grouped_reactions

Grouped reactions with counts

is_from_me

Easy message alignment with is_from_me

tags

Conversation tags included

The Chat API returns the same data as standard endpoints but with additional fields optimized for UI rendering. You can also use ?format=chat on standard endpoints.

/api/v1/conversations?format=chat
GET /api/v1/chat/conversations

Lists conversations with tags, profile pictures, and unread counts optimized for chat list UI.

Query Parameters

Field Type Description
instance_id string Filter by instance (UUID)
search string Search by name or number
unread boolean Show only unread conversations
per_page integer Items per page (max 100)

Example

curl -X GET "https://zapini.app/api/v1/chat/conversations?unread=true" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440045",
      "contact_number": "5521999999999",
      "display_name": "John Doe",
      "is_group": false,
      "profile_picture_url": "https://...",
      "last_message": "Hello!",
      "last_message_at": "2025-12-16T10:00:00Z",
      "unread_count": 3,
      "tags": [
        {"id": "bf287f4d-037c-4280-8413-c7b7d08df5a0", "name": "VIP", "color": "#f59e0b"}
      ],
      "instance": {
        "uuid": "21ed5c9b-51a0-4569-85db-05433ea414b7",
        "phone_number": "5511988887777",
        "status": "connected"
      }
    }
  ],
  "meta": {
    "pagination": {
      "total": 50,
      "per_page": 15,
      "current_page": 1,
      "last_page": 4
    }
  }
}
GET /api/v1/chat/conversations/{uuid}/messages

Returns messages with formatted_body (resolved @mentions) and grouped reactions.

Query Parameters

Field Type Description
before_id integer Messages before this ID
after_id integer Messages after this ID
limit integer Message limit (max 100)

Example

curl -X GET "https://zapini.app/api/v1/chat/conversations/550e8400-e29b-41d4-a716-446655440045/messages?limit=50" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "data": {
    "messages": [
      {
        "id": 456,
        "unique_id": "msg-abc-123",
        "direction": "incoming",
        "is_from_me": false,
        "message_body": "Ola @5521999999999!",
        "formatted_body": "Ola <span class=\"mention\" data-phone=\"5521999999999\">@John Doe</span>!",
        "mentioned_jids": ["5521999999999@s.whatsapp.net"],
        "sender_name": "Maria",
        "status": "read",
        "grouped_reactions": [
          {
            "emoji": "👍",
            "count": 2,
            "has_my_reaction": true,
            "reactors": ["5521988887777", "5521966665555"],
            "reactor_names": ["Carlos", "Ana"]
          }
        ],
        "created_at": "2025-12-16T10:00:00Z"
      }
    ],
    "has_more": true,
    "oldest_id": 400,
    "newest_id": 456
  }
}

Key Features

formatted_body

Message text with @mentions resolved to contact names. Returns HTML with clickable spans.

Hello @John Smith!
is_from_me

Boolean indicating if the message was sent by your instance. Use for message alignment.

grouped_reactions

Reactions grouped by emoji with counts and reactor information.

{"emoji": "👍", "count": 2, "has_my_reaction": true}
mentioned_jids

Array of WhatsApp JIDs mentioned in the message.

POST /api/v1/chat/send

Sends a text message and returns the message in chat-optimized format.

Parameters

Field Type Required Description
instance_id string Yes Instance UUID (required)
recipient string Yes Recipient phone number with country code
message string Yes Text message content
reply_to string No Message ID to reply to

Example

curl -X POST "https://zapini.app/api/v1/chat/send" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "777",
    "recipient": "5521999999999",
    "message": "Hello from Chat API!"
  }'
POST /api/v1/chat/send-media

Sends media (image, video, audio, document) and returns chat-optimized response.

Parameters

Field Type Required Description
instance_id string Yes Instance UUID (required)
recipient string Yes Recipient phone number with country code
media_url string Yes URL of the media file to send
media_type string Yes Type of media (image, video, audio, document)
caption string No Caption for image/video

Example

curl -X POST "https://zapini.app/api/v1/chat/send-media" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_id": "777",
    "recipient": "5521999999999",
    "media_url": "https://example.com/image.jpg",
    "media_type": "image",
    "caption": "Check this out!"
  }'
PATCH /api/v1/chat/messages/{uuid}

Edits a sent message content.

Parameters

Field Type Required Description
message string Yes New message content

Example

curl -X PATCH "https://zapini.app/api/v1/chat/messages/msg-abc-123" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"message": "Updated message content"}'
DELETE /api/v1/chat/messages/{uuid}

Deletes a sent message.

Example

curl -X DELETE "https://zapini.app/api/v1/chat/messages/msg-abc-123" \
  -H "Authorization: Bearer {token}"
POST /api/v1/chat/messages/{uuid}/reaction

Adds an emoji reaction to a message.

Parameters

Field Type Required Description
emoji string Yes Emoji to react with

Example

curl -X POST "https://zapini.app/api/v1/chat/messages/msg-abc-123/reaction" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"emoji": "👍"}'
DELETE /api/v1/chat/messages/{uuid}/reaction

Removes a reaction from a message.

Example

curl -X DELETE "https://zapini.app/api/v1/chat/messages/msg-abc-123/reaction" \
  -H "Authorization: Bearer {token}"
POST /api/v1/chat/conversations/{uuid}/mark-read

Marks a conversation as read.

Example

curl -X POST "https://zapini.app/api/v1/chat/conversations/550e8400-e29b-41d4-a716-446655440045/mark-read" \
  -H "Authorization: Bearer {token}"
POST /api/v1/chat/conversations/{uuid}/archive

Archives a conversation.

Example

curl -X POST "https://zapini.app/api/v1/chat/conversations/550e8400-e29b-41d4-a716-446655440045/archive" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "message": "Conversation archived.",
  "data": {
    "archived_id": "550e8400-e29b-41d4-a716-446655440045",
    "archived_at": "2025-12-29T12:00:00.000000Z"
  }
}
DELETE /api/v1/chat/conversations/{uuid}/archive

Restores an archived conversation back to active status.

The UUID must be from an archived conversation. Use GET /conversations/archived to list archived conversations.

Example

curl -X DELETE "https://zapini.app/api/v1/chat/conversations/550e8400-e29b-41d4-a716-446655440045/archive" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "message": "Conversation restored.",
  "data": {
    "conversation_id": "550e8400-e29b-41d4-a716-446655440045",
    "restored": true
  }
}
POST /api/v1/chat/conversations/{uuid}/pause-automation

Pause automation for a conversation to allow manual messaging.

Request Body

Field Type Required Description
reason string No Optional reason for pausing automation

Example

curl -X POST "https://zapini.app/api/v1/chat/conversations/550e8400-e29b-41d4-a716-446655440045/pause-automation" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Manual takeover"}'
POST /api/v1/chat/conversations/{uuid}/resume-automation

Resume automation for a conversation, returning control to the automated system.

Example

curl -X POST "https://zapini.app/api/v1/chat/conversations/550e8400-e29b-41d4-a716-446655440045/resume-automation" \
  -H "Authorization: Bearer {token}"

Audio Transcription

Transcription fields are also included in the message object returned by the messages endpoint. Audio messages with auto-transcribe enabled will have transcriptions populated automatically.

GET /api/v1/chat/messages/{uuid}/transcription

Get the transcription status and text for an audio message.

Example

curl -X GET "https://zapini.app/api/v1/chat/messages/msg-abc-123/transcription" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "data": {
    "message_id": "msg-abc-123",
    "audio_transcription": "Olá, tudo bem? Gostaria de saber mais sobre o produto.",
    "transcription_status": "completed",
    "transcription_language": "pt",
    "transcription_error": null,
    "transcription_completed_at": "2026-02-21T10:30:00.000000Z"
  }
}

Response Fields

Field Type Description
audio_transcription string|null The transcribed text (null if not yet completed)
transcription_status string|null Status: pending, processing, completed, or failed
transcription_language string|null Detected or configured language code (e.g. pt, en, es)
transcription_error string|null Error message if transcription failed
transcription_completed_at string|null Timestamp when transcription was completed
POST /api/v1/chat/messages/{uuid}/transcription

Request transcription for an audio message. If already completed, returns the existing transcription. Supports Whisper, Gemini, and ElevenLabs providers.

Example

curl -X POST "https://zapini.app/api/v1/chat/messages/msg-abc-123/transcription" \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "message": "Transcription queued successfully.",
  "data": {
    "message_id": "msg-abc-123",
    "transcription_status": "pending"
  }
}

Automations

IMPORTANT

Important Notice about Automations

If your instance has active automations (flows or integrations), sending messages via API may be blocked. Read this section to understand how it works.

What are Automations?

Automations are automated flows that respond to messages automatically. The system has two types of automation:

Flows

Conversation flows created in the visual editor that respond automatically based on rules and conditions.

Integrations

Connections with external systems (webhooks, APIs, AI) that process and respond to messages automatically.

Message Blocking

When a conversation has active automation, sending messages via API is blocked to avoid conflicts between automatic and manual responses.

Error Response

{
  "success": false,
  "error": {
    "code": "AUTOMATION_ACTIVE",
    "message": "Cannot send messages. This conversation has active automation. Pause the automation first to send messages manually.",
    "conversation_id": 123
  }
}

When is Sending Blocked?

  • • The instance has an active flow or integration
  • • The conversation was not manually paused
  • • The conversation is still being managed by automation

How to Send Messages with Active Automation

To send messages manually when automation is active, you need to pause the automation for the specific conversation:

1

Check the Status

Use the conversation details endpoint to check the automation_status field.

2

Pause the Automation

If automation_status is "active", use the pause endpoint to allow manual messages.

3

Send the Message

After pausing, you can send messages normally via API.

GET /api/v1/chat/conversations/{uuid}

Check the automation status of a conversation before attempting to send messages.

Response Fields

Field Type Description
automation_status string Current automation status (active or paused)
can_send_manual_message boolean Whether you can send manual messages
automation_paused_at datetime|null Date/time when automation was paused

Status Values

Status Description Can Send via API?
active Automation is responding to messages automatically No
paused Automation paused, user has taken control Yes
POST /api/v1/chat/conversations/{uuid}/pause-automation

Pauses automation to allow sending manual messages via API.

Request Body (optional)

Field Type Description
reason string Optional reason for pausing (e.g., "Manual intervention required")

Example

curl -X POST https://instance-{id}.zapini.app/api/v1/chat/conversations/a1b2c3d4-e5f6-7890-abcd-ef1234567890/pause-automation \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Manual intervention required"}'

Response Example

{
  "success": true,
  "message": "Automation paused successfully",
  "data": {
    "conversation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "automation_paused": true,
    "paused_at": "2025-01-15T10:30:00+00:00",
    "paused_by": "John Doe",
    "reason": "Manual intervention required"
  }
}
POST /api/v1/chat/conversations/{uuid}/resume-automation

Resumes automation, returning control to the automated system.

Example

curl -X POST https://instance-{id}.zapini.app/api/v1/chat/conversations/a1b2c3d4-e5f6-7890-abcd-ef1234567890/resume-automation \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json"

Response Example

{
  "success": true,
  "message": "Automation resumed successfully",
  "data": {
    "conversation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "automation_paused": false,
    "resumed_at": "2025-01-15T11:00:00+00:00"
  }
}

Bulk Operations

Pause or resume automation for multiple conversations at once. Useful for maintenance, campaigns, or batch processing. Maximum 100 conversations per request.

POST /api/v1/conversations/automation/bulk-pause

Pauses automation for multiple conversations at once. Skips conversations that are already paused or have no active automation.

Request Body

Field Type Required Description
conversation_ids array Yes Array of conversation UUIDs (max 100)
reason string No Optional reason for pausing (e.g., "Manual intervention required")

Example

curl -X POST https://instance-{id}.zapini.app/api/v1/conversations/automation/bulk-pause \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_ids": [
      "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    ],
    "reason": "Bulk pause for maintenance"
  }'

Response

{
  "success": true,
  "message": "2 conversations paused",
  "data": {
    "paused": 2,
    "skipped": 0,
    "errors": 0
  }
}
POST /api/v1/conversations/automation/bulk-resume

Resumes automation for multiple conversations at once. Skips conversations that are not paused or have no active automation.

Request Body

Field Type Required Description
conversation_ids array Yes Array of conversation UUIDs (max 100)

Example

curl -X POST https://instance-{id}.zapini.app/api/v1/conversations/automation/bulk-resume \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_ids": [
      "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "b2c3d4e5-f6a7-8901-bcde-f12345678901"
    ]
  }'

Response

{
  "success": true,
  "message": "2 automations resumed",
  "data": {
    "resumed": 2,
    "skipped": 0,
    "errors": 0
  }
}

Best Practices

  • Always check can_send_manual_message before sending messages to avoid errors.
  • Pause automation only when necessary for human intervention.
  • Resume automation after manual service to maintain consistent experience.

Voice & IVR API

62 endpoints

Voice API Overview

The Voice API lets you programmatically manage your entire telephony infrastructure: phone numbers, IVR configuration, calls, queues, callbacks, agent skills and voice cloning.

Base URL

https://zapini.app/api/v1/voice

Authentication

Bearer Token Auth + Twilio Voice Permission

Endpoints

62 endpoints available

This API requires the Twilio Voice feature to be enabled on your tenant. Contact your administrator to activate it.

Phone Numbers

Manage phone numbers: register, configure call handling mode (AI, human, IVR), recording, SIP and more.

Available call handling modes

ai_onlyAI Only - AI handles all calls automatically
human_onlyHuman Only - Calls routed to human agents via WebRTC
ai_with_handoffAI with Handoff - AI answers and can transfer to human
ivr_menuIVR Menu - Interactive voice menu with numeric options
GET /voice/numbers

Manage phone numbers: register, configure call handling mode (AI, human, IVR), recording, SIP and more.

Example

curl -X GET https://zapini.app/api/v1/voice/numbers \
  -H "Authorization: Bearer {token}"

Response

{
  "success": true,
  "data": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "phone_number": "+5511999999999",
      "friendly_name": "Main Line",
      "status": "active",
      "connection_type": "twilio",
      "call_handling_mode": "ai_only",
      "ai_enabled": true,
      "recording_enabled": false,
      "ivr_enabled": false,
      "created_at": "2026-02-14T10:00:00Z"
    }
  ]
}
POST /voice/numbers

Register a new phone number.

Parameters

ParameterTypeRequiredDescription
phone_numberstringyesE.164 format (+5511999999999)
friendly_namestringnoDisplay name
connection_typestringnotwilio, asterisk_sip, asterisk_hardphone

Example

curl -X POST https://zapini.app/api/v1/voice/numbers \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+5511999999999",
    "friendly_name": "Main Line",
    "connection_type": "twilio"
  }'
GET /voice/numbers/{uuid}

Get full details of a phone number including AI config, SIP settings and business hours summary.

PATCH /voice/numbers/{uuid}

Update phone number settings.

Parameters

ParameterTypeDescription
friendly_namestringDisplay name
call_handling_modestringai_only, human_only, ai_with_handoff, ivr_menu
ai_system_promptstringAI system prompt for calls
ai_voicestringAI voice ID
recording_enabledbooleanEnable call recording
sip_enabledbooleanEnable SIP
statusstringactive, inactive
DELETE /voice/numbers/{uuid}

Delete/release a phone number. Returns 204 on success.

Business Hours & Holidays

Configure business hours and holidays for each number. Calls outside hours can be automatically redirected.

GET /voice/numbers/{uuid}/business-hours

Get business hours schedule and current status (open/closed).

Response

{
  "success": true,
  "data": {
    "enabled": true,
    "timezone": "America/Sao_Paulo",
    "is_currently_open": true,
    "schedule": {
      "monday": { "enabled": true, "open": "09:00", "close": "18:00" },
      "tuesday": { "enabled": true, "open": "09:00", "close": "18:00" },
      "wednesday": { "enabled": true, "open": "09:00", "close": "18:00" },
      "thursday": { "enabled": true, "open": "09:00", "close": "18:00" },
      "friday": { "enabled": true, "open": "09:00", "close": "17:00" },
      "saturday": { "enabled": false },
      "sunday": { "enabled": false }
    },
    "outside_hours_action": "voicemail",
    "outside_hours_message": "We are currently closed."
  }
}
PUT /voice/numbers/{uuid}/business-hours

Set full business hours schedule. Send the complete schedule object.

GET /voice/numbers/{uuid}/holidays

Manage holidays with custom messages. Supports recurring (annual) and specific date holidays.

Response

{
  "success": true,
  "data": {
    "holidays": [
      {
        "index": 0,
        "name": "Christmas",
        "date": "2026-12-25",
        "recurring": true,
        "message": "Merry Christmas!"
      }
    ]
  }
}
POST /voice/numbers/{uuid}/holidays

Add a single holiday. Required: name, date. Optional: recurring, message.

PUT /voice/numbers/{uuid}/holidays

Replace all holidays. Send an array of holiday objects.

DELETE /voice/numbers/{uuid}/holidays/{index}

Remove a holiday by its index (0-based).

IVR Configuration

Configure interactive voice menus with numeric options, TTS messages, data collection, transfers and more.

IVR Option Types

collect_cpfCollect caller CPF
collect_numberCollect dialed number
record_voiceRecord voice message
transfer_agentTransfer to human agent
transfer_aiTransfer to AI service
transfer_externalTransfer to external number
play_messagePlay message
submenuOpen submenu
callbackRequest callback
scheduleSchedule appointment
customCustom action
GET /voice/numbers/{uuid}/ivr

Get full IVR configuration including messages, timeouts and options.

Response

{
  "success": true,
  "data": {
    "ivr_enabled": true,
    "ivr_welcome_message": "Welcome to our company.",
    "ivr_menu_intro": "Press 1 for sales, 2 for support.",
    "ivr_invalid_option_message": "Invalid option.",
    "ivr_goodbye_message": "Goodbye!",
    "ivr_input_timeout": 5,
    "ivr_max_attempts": 3,
    "options": [
      {
        "uuid": "a1b2c3d4...",
        "digit": "1",
        "label": "Sales",
        "type": "transfer_agent",
        "is_enabled": true,
        "order": 1
      }
    ]
  }
}
PUT /voice/numbers/{uuid}/ivr

Update IVR configuration.

Parameters

ParameterTypeDescription
ivr_enabledbooleanIVR configuration fields
ivr_welcome_messagestringWelcome message played on answer
ivr_menu_introstringMenu text with available options
ivr_invalid_option_messagestringMessage for invalid option
ivr_goodbye_messagestringGoodbye message
ivr_input_timeoutintegerInput wait timeout (1-30 seconds)
ivr_max_attemptsintegerMaximum invalid attempts (1-10)
GET /voice/numbers/{uuid}/ivr/types

List all available IVR option types with descriptions.

POST /voice/numbers/{uuid}/ivr/options

Create a new IVR menu option.

Example

curl -X POST https://zapini.app/api/v1/voice/numbers/{uuid}/ivr/options \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "digit": "1",
    "label": "Sales Department",
    "type": "transfer_agent",
    "message": "Transferring you to our sales team.",
    "is_enabled": true
  }'
GET /voice/numbers/{uuid}/ivr/options

List all IVR menu options for a number, ordered by position.

PATCH /voice/numbers/{uuid}/ivr/options/{optionUuid}

Update an IVR option (digit, label, type, message, enabled).

DELETE /voice/numbers/{uuid}/ivr/options/{optionUuid}

Delete an IVR option.

POST /voice/numbers/{uuid}/ivr/options/reorder

Reorder IVR options. Send array of UUIDs in desired order.

{ "order": ["uuid-option-2", "uuid-option-1", "uuid-option-3"] }
POST /voice/numbers/{uuid}/ivr/regenerate-audio

Regenerate TTS audio cache for IVR messages. Optional: voice_id, language.

VIP Callers

Manage priority callers with custom routing. VIP callers can skip the queue or receive differentiated service.

Priority levels

vipVIP - Highest priority, skips queue
priorityPriority - Preferential service
standardStandard - Normal service
blockedBlocked - Calls automatically rejected
GET /voice/numbers/{uuid}/vip-callers

List all VIP callers for a phone number.

POST /voice/numbers/{uuid}/vip-callers

Add a VIP caller.

Example

curl -X POST https://zapini.app/api/v1/voice/numbers/{uuid}/vip-callers \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+5511988887777",
    "name": "John CEO",
    "priority": "vip",
    "notes": "Always connect immediately"
  }'
GET /voice/numbers/{uuid}/vip-callers/check/{phone}

Check if a phone number is in the VIP list. Returns VIP details or is_vip: false.

PATCH /voice/numbers/{uuid}/vip-callers/{vipUuid} | DELETE /voice/numbers/{uuid}/vip-callers/{vipUuid}

Update or delete a VIP caller by UUID.

Queue Management

Configure and monitor call queues with hold music, position announcements and automatic callback.

GET /voice/numbers/{uuid}/queue

Get queue status, configuration and metrics.

Response

{
  "success": true,
  "data": {
    "config": {
      "queue_enabled": true,
      "max_queue_size": 10,
      "max_wait_time": 300,
      "hold_music_url": null,
      "announce_position": true,
      "callback_enabled": true
    },
    "status": {
      "active_entries": 3,
      "waiting_count": 2,
      "connected_count": 1
    }
  }
}
PATCH /voice/numbers/{uuid}/queue

Update queue configuration (max_queue_size, max_wait_time, hold_music_url, announce_position, callback_enabled).

GET /voice/numbers/{uuid}/queue/entries | DELETE /voice/numbers/{uuid}/queue/entries/{id}

List active queue entries or remove a specific entry from the queue.

Calls

Initiate, monitor and manage calls. Includes AI transfer, statistics and detailed costs.

GET /voice/calls

List calls with filters.

Available filters

ParameterTypeDescription
directionstringinbound, outbound
statusstringringing, in-progress, completed, failed, etc.
number_uuidstringFilter by phone number UUID
date_fromdateYYYY-MM-DD
date_todateYYYY-MM-DD
per_pageintegerResults per page (default: 25)

Example

curl -X GET "https://zapini.app/api/v1/voice/calls?direction=inbound&status=completed&per_page=10" \
  -H "Authorization: Bearer {token}"
POST /voice/calls

Initiate an outbound call.

Example

curl -X POST https://zapini.app/api/v1/voice/calls \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "from_number_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "to": "+5511988887777",
    "record": true
  }'
GET /voice/calls/statistics

Get call statistics: total, by direction, average duration, costs.

Response

{
  "success": true,
  "data": {
    "period": "monthly",
    "total_calls": 150,
    "inbound": 90,
    "outbound": 60,
    "total_duration_seconds": 45000,
    "average_duration_seconds": 300,
    "total_cost": 75.50,
    "minutes_used": 750,
    "minutes_limit": 1000,
    "minutes_remaining": 250
  }
}
GET /voice/calls/{uuid}

Get detailed call information with duration, costs, recording URL and transcript.

Call Actions:

POST /voice/calls/{uuid}/end
POST /voice/calls/{uuid}/transfer-to-ai
POST /voice/calls/{uuid}/reject

End an active call, transfer it to AI, or reject an incoming call.

Callbacks

Manage callback requests: list, execute, cancel and reschedule.

GET /voice/callbacks

List callback requests. Filters: status (pending, completed, cancelled, expired), number_uuid, date_from, date_to.

Example

curl -X GET "https://zapini.app/api/v1/voice/callbacks?status=pending" \
  -H "Authorization: Bearer {token}"

Callback Actions:

GET /voice/callbacks/{uuid}
POST /voice/callbacks/{uuid}/execute
POST /voice/callbacks/{uuid}/cancel
POST /voice/callbacks/{uuid}/reschedule

Get details, execute now, cancel, or reschedule a callback.

Reschedule requires: scheduled_for (ISO 8601 datetime)

Agent Skills

Manage agent competencies for intelligent skill-based call routing.

GET /voice/agents/skill-types

Get available skill types (sales, support, billing, technical, etc.).

Agent Skills CRUD:

GET /voice/agents/skills
GET /voice/agents/{userId}/skills
POST /voice/agents/{userId}/skills
PATCH /voice/agents/{userId}/skills/{skillId}
DELETE /voice/agents/{userId}/skills/{skillId}

Manage agent skills. Add skill requires: skill_type, proficiency (1-5).

Example

curl -X POST https://zapini.app/api/v1/voice/agents/{userId}/skills \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "skill_type": "sales",
    "proficiency": 5
  }'

Cloned Voices

Clone voices using AI for IVR and automated service. Upload audio samples to create custom voices.

GET /voice/voices

List all cloned voices for the tenant.

POST /voice/voices

Clone a new voice from audio samples (multipart/form-data).

Example

curl -X POST https://zapini.app/api/v1/voice/voices \
  -H "Authorization: Bearer {token}" \
  -F "name=My Voice Clone" \
  -F "description=Custom voice for IVR" \
  -F "samples[]=@sample1.mp3" \
  -F "samples[]=@sample2.mp3"
GET /voice/voices/{uuid} | PATCH /voice/voices/{uuid} | DELETE /voice/voices/{uuid}

Get details, update name/description, or delete a cloned voice.

Twilio Credentials

Manage Twilio access credentials: Account SID, Auth Token and API Keys for WebRTC.

GET /voice/credentials

Get credential status (masked values, never exposes secrets).

Response

{
  "success": true,
  "data": {
    "configured": true,
    "is_verified": true,
    "account_sid_masked": "AC****1234",
    "has_api_keys": true,
    "api_key_sid_masked": "SK****5678",
    "created_at": "2026-02-14T10:00:00Z"
  }
}
POST /voice/credentials

Save Twilio credentials.

Parameters

ParameterRequiredDescription
account_sidyesTwilio Account SID (ACxxxxxxx)
auth_tokenyesTwilio Auth Token
api_key_sidnoAPI Key SID for WebRTC (SKxxxxxxx)
api_key_secretnoAPI Key Secret for WebRTC
POST /voice/credentials/verify | PATCH /voice/credentials | DELETE /voice/credentials

Verify credentials against Twilio API, update, or remove credentials entirely.

Audio & WebRTC

Upload audio for IVR and generate TTS previews. Get WebRTC tokens for softphone.

POST /voice/audio/upload

Upload audio file for IVR greetings, hold music, etc. (multipart/form-data)

Example

curl -X POST https://zapini.app/api/v1/voice/audio/upload \
  -H "Authorization: Bearer {token}" \
  -F "audio=@greeting.mp3" \
  -F "type=ivr_greeting"
POST /voice/audio/tts-preview

Generate a TTS (Text-to-Speech) audio preview.

Example

curl -X POST https://zapini.app/api/v1/voice/audio/tts-preview \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Welcome to our company. How can I help you?",
    "voice_id": "optional-elevenlabs-voice-id",
    "language": "pt-BR"
  }'
POST /voice/token

Get WebRTC capability token for browser-based softphone.

Response

{
  "success": true,
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
    "identity": "tenant_29",
    "expires_in": 3600
  }
}

Error Codes

CodeHTTPDescription
NO_VOICE_ACCESS403Twilio Voice feature not enabled on tenant
NO_CREDENTIALS400Twilio credentials not configured
NUMBER_NOT_FOUND404Phone number not found or unauthorized
CALL_NOT_FOUND404Call not found or unauthorized
MINUTES_EXCEEDED429Monthly minutes limit exceeded
CALL_NOT_ACTIVE400Call is not in progress
CALLBACK_EXPIRED400Callback expired or already executed
IVR_NOT_ENABLED400IVR is not enabled on this number

Complete Setup

To use the Voice API, follow these steps:

1

1. Save your Twilio credentials via POST /credentials

2

2. Verify credentials via POST /credentials/verify

3

3. Register a number via POST /numbers

4

4. Configure call handling mode (AI, human or IVR)

5

5. If IVR: configure options via POST /numbers/{uuid}/ivr/options

6

6. Make calls via POST /calls or receive via WebRTC

Kanban API

21 endpoints

Kanban API

Manage Kanban boards, columns, and leads programmatically. Automate your sales pipeline and integrate with external CRM or reporting tools.

Base URL

/api/v1/kanban

Authentication

Bearer Token (sk_*)

Endpoints

21 endpoints

Kanban access required

This API requires kanban_enabled on your tenant account. Contact your administrator to enable Kanban.

Boards

GET /api/v1/kanban/boards List all Kanban boards for the current instance.
curl -s -H "Authorization: Bearer sk_your_token" \
  "https://zapini.app/api/v1/kanban/boards"
POST /api/v1/kanban/boards Create a new Kanban board with default columns.
curl -s -X POST \
  -H "Authorization: Bearer sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{"name":"Sales Pipeline","is_default":true}' \
  "https://zapini.app/api/v1/kanban/boards"
Body: name*, description, is_default
GET /api/v1/kanban/boards/{uuid} Get board details including columns and statistics.
// Response includes stats + columns
{
  "uuid": "...",
  "name": "Sales Pipeline",
  "stats": {
    "total_leads": 12, "open_leads": 9, "won_leads": 2, "lost_leads": 1,
    "total_value": 15000.00, "won_value": 5000.00,
    "conversion_rate": 66.7, "avg_time_to_close": 14.5
  },
  "columns": [...]
}
PUT /api/v1/kanban/boards/{uuid}

Update board name, description, or settings.

DELETE /api/v1/kanban/boards/{uuid}

Delete a board and all its columns and leads.

Columns

GET /api/v1/kanban/boards/{uuid}/columns List columns for a board (ordered by position).
POST /api/v1/kanban/boards/{uuid}/columns Create a new column in a board.
POST /api/v1/kanban/boards/{uuid}/columns/reorder Reorder columns by providing ordered array of UUIDs.
PUT /api/v1/kanban/columns/{uuid} Update column name, color, or settings.
DELETE /api/v1/kanban/columns/{uuid} Delete a column, optionally moving leads to another column.

Example — Reorder Columns

curl -s -X POST \
  -H "Authorization: Bearer sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{"order":["col-uuid-1","col-uuid-2","col-uuid-3"]}' \
  "https://zapini.app/api/v1/kanban/boards/{board-uuid}/columns/reorder"

Leads

GET /api/v1/kanban/boards/{uuid}/leads List leads in a board with optional filters.
POST /api/v1/kanban/leads Create a new lead in a board.
GET /api/v1/kanban/leads/{uuid} Get lead details including notes, custom fields, and AI analysis.
PUT /api/v1/kanban/leads/{uuid} Update lead fields (title, value, priority, etc.).
DELETE /api/v1/kanban/leads/{uuid} Soft-delete a lead.
POST /api/v1/kanban/leads/{uuid}/move Move a lead to a different column.
POST /api/v1/kanban/leads/{uuid}/won Mark a lead as won.
POST /api/v1/kanban/leads/{uuid}/lost Mark a lead as lost with optional reason.
POST /api/v1/kanban/leads/{uuid}/note Add a timestamped note to a lead.
GET /api/v1/kanban/leads/{uuid}/activities Get the activity timeline for a lead.
POST /api/v1/kanban/leads/{uuid}/ai-qualify Run AI qualification analysis on a lead.

Example — Create a new lead in a board.

curl -s -X POST \
  -H "Authorization: Bearer sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "board_uuid": "board-uuid-here",
    "title": "John Doe - Pro Plan",
    "phone_number": "5511999999999",
    "email": "john@example.com",
    "value": 299.00,
    "priority": "high",
    "notes": "Interested in annual subscription"
  }' \
  "https://zapini.app/api/v1/kanban/leads"

Response:

{
  "success": true,
  "data": {
    "uuid": "...",
    "title": "John Doe - Pro Plan",
    "phone_number": "5511999999999",
    "value": "299.00",
    "value_formatted": "R$ 299,00",
    "priority": "high",
    "priority_label": "High",
    "source": "api",
    "ai_score": null,
    "is_open": true, "is_won": false, "is_lost": false,
    "column": { "uuid": "...", "name": "New Lead", "color": "#3B82F6" }
  }
}

Query Parameters — GET /boards/{uuid}/leads

Field Description
statusopen | won | lost | all (default: open)
prioritylow | medium | high | urgent
column_uuidFilter by column UUID
searchSearch by name or number

Calendar API

9 endpoints

Calendar API

Manage appointments and calendar events. Create, update, and track appointment status transitions programmatically.

Base URL

/api/v1/calendar

Authentication

Bearer Token (sk_*)

Endpoints

9 endpoints

Appointment Statuses

scheduled Initial status — appointment is booked
confirmed Client confirmed attendance
completed Appointment was completed
cancelled Appointment was cancelled
no_show Client did not show up

Appointments

GET /api/v1/calendar/appointments List appointments for a date range (defaults to current month).
POST /api/v1/calendar/appointments Create a new appointment.
GET /api/v1/calendar/appointments/{uuid} Get appointment details.
PUT /api/v1/calendar/appointments/{uuid} Update appointment details or status.
DELETE /api/v1/calendar/appointments/{uuid} Delete an appointment.
POST /api/v1/calendar/appointments/{uuid}/confirm Transition appointment status to confirmed.
POST /api/v1/calendar/appointments/{uuid}/complete Transition appointment status to completed.
POST /api/v1/calendar/appointments/{uuid}/cancel Cancel an appointment (cannot cancel already completed).
POST /api/v1/calendar/appointments/{uuid}/to-kanban Create a Kanban lead from this appointment.

Example — Create Appointment

curl -s -X POST \
  -H "Authorization: Bearer sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Consultation with John Doe",
    "client_name": "John Doe",
    "client_phone": "5511999999999",
    "client_email": "john@example.com",
    "starts_at": "2026-05-01T10:00:00",
    "ends_at": "2026-05-01T11:00:00",
    "location": "Online - Google Meet",
    "reminder_minutes": 30
  }' \
  "https://zapini.app/api/v1/calendar/appointments"

Response:

{
  "success": true,
  "data": {
    "uuid": "...",
    "title": "Consultation with John Doe",
    "client_name": "John Doe",
    "client_phone": "5511999999999",
    "starts_at": "2026-05-01T10:00:00+00:00",
    "ends_at": "2026-05-01T11:00:00+00:00",
    "duration_minutes": 60,
    "status": "scheduled",
    "color": "#3b82f6",
    "reminder_minutes": 30,
    "created_at": "2026-01-01T00:00:00+00:00"
  }
}

Query Parameters — GET /calendar/appointments

Field Description Default
startStart date (ISO 8601)Start of month
endEnd date (ISO 8601)End of month
statusscheduled | confirmed | completed | cancelled | no_show
per_pageItems per page (max 100)50

to-kanban endpoint

Converts an appointment into a Kanban lead. Requires kanban_enabled on your tenant. Optionally specify board_uuid; otherwise the default board is used.

curl -s -X POST \
  -H "Authorization: Bearer sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{"board_uuid": "optional-board-uuid"}' \
  "https://zapini.app/api/v1/calendar/appointments/{uuid}/to-kanban"

AI Functions API

9 endpoints

AI Functions API

Manage AI functions (webhook-based tools) that your AI agent can call during conversations. Create, configure, test, and monitor custom functions that extend your AI agent's capabilities.

⚡ Requires an active AI Agent integration on your account.

Endpoints

Method Endpoint Description
GET/api/v1/ai-functionsList AI Functions
POST/api/v1/ai-functionsCreate AI Function
GET/api/v1/ai-functions/{uuid}Get AI Function
PUT/api/v1/ai-functions/{uuid}Update AI Function
DELETE/api/v1/ai-functions/{uuid}Delete AI Function
POST/api/v1/ai-functions/{uuid}/toggleToggle AI Function
POST/api/v1/ai-functions/{uuid}/testTest AI Function
GET/api/v1/ai-functions/{uuid}/executionsList Executions
GET/api/v1/ai-functions/executions/{uuid}Get Execution Details
GET /api/v1/ai-functions

Returns a paginated list of all AI functions for your account.

Query Parameters

integration_uuidFilter by integration UUID
typeFilter by function type
enabledFilter by enabled status
searchSearch by name or description
per_pageResults per page (max 100, default 20)

Example

curl -X GET "https://zapini.app/api/v1/ai-functions?type=fetch_data&enabled=true" \
  -H "Authorization: Bearer {token}"
POST /api/v1/ai-functions

Creates a new AI function with optional parameters. The function must be attached to an AI Agent integration.

Body Parameters

integration_uuid *UUID of the AI Agent integration
name *Function name (lowercase, underscores only)
display_name *User-friendly display name
description *Description shown to the AI agent
type *Function type: fetch_data, collect_submit, action
endpoint_urlWebhook URL to call
http_methodHTTP method (GET, POST, PUT, PATCH, DELETE)
auth_typeAuthentication type: none, bearer, basic, api_key, custom
parametersArray of function parameters
is_enabledWhether the function is active

Example

curl -X POST "https://zapini.app/api/v1/ai-functions" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "integration_uuid": "abc-123-def",
    "name": "check_order_status",
    "display_name": "Check Order Status",
    "description": "Checks the status of a customer order by order number",
    "type": "fetch_data",
    "endpoint_url": "https://api.myshop.com/orders/status",
    "http_method": "GET",
    "auth_type": "bearer",
    "auth_config": {"token": "my-shop-api-key"},
    "parameters": [
      {
        "name": "order_number",
        "display_name": "Order Number",
        "description": "The customer order number",
        "type": "string",
        "is_required": true,
        "collect_from_user": true
      }
    ]
  }'
POST /api/v1/ai-functions/{uuid}/toggle

Toggles the enabled/disabled state of an AI function.

curl -X POST "https://zapini.app/api/v1/ai-functions/{uuid}/toggle" \
  -H "Authorization: Bearer {token}"
POST /api/v1/ai-functions/{uuid}/test

Executes a test call to the function's endpoint with the provided parameters.

curl -X POST "https://zapini.app/api/v1/ai-functions/{uuid}/test" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"parameters": {"order_number": "ORD-12345"}}'

Error Codes

AI_AGENT_NOT_ENABLED403 — AI_AGENT_NOT_ENABLED — No active AI Agent integration
DUPLICATE_NAME422 — DUPLICATE_NAME — Function name already exists
ACTIVE_EXECUTIONS409 — ACTIVE_EXECUTIONS — Cannot delete while executions are in progress
INVALID_INTEGRATION_TYPE422 — INVALID_INTEGRATION_TYPE — Integration is not of AI Agent type

External Functions API

8 endpoints

External Functions API

Manage external functions — webhook endpoints that allow external systems to trigger WhatsApp actions (send messages, manage contacts, control automations). Each function gets a unique API key for authentication.

⚡ Requires an active AI Agent integration on your account.

Endpoints

Method Endpoint Description
GET/api/v1/external-functionsList External Functions
POST/api/v1/external-functionsCreate External Function
GET/api/v1/external-functions/{uuid}Get External Function
PUT/api/v1/external-functions/{uuid}Update External Function
DELETE/api/v1/external-functions/{uuid}Delete External Function
POST/api/v1/external-functions/{uuid}/toggleToggle External Function
POST/api/v1/external-functions/{uuid}/regenerate-keyRegenerate API Key
GET/api/v1/external-functions/{uuid}/logsList Logs
POST /api/v1/external-functions

Creates a new external function with an auto-generated API key. The plain API key is only returned once — store it securely.

Body Parameters

instance_uuid *UUID of the WhatsApp instance
name *Function name
slug *URL slug (lowercase, hyphens only)
action_type *Action type: send_message, send_buttons, send_media, create_contact, update_contact, create_lead, update_lead, pause_automation, resume_automation
descriptionFunction description
configAction-specific configuration
rate_limitMaximum calls per day (default: 1000)
allowed_ipsArray of allowed IP addresses (empty = all allowed)
is_enabledWhether the function is active

Example

curl -X POST "https://zapini.app/api/v1/external-functions" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_uuid": "abc-123-def",
    "name": "CRM Order Notification",
    "slug": "crm-order-notify",
    "action_type": "send_message",
    "description": "Sends order status updates from CRM",
    "config": {
      "message_template": "Order {{order_id}}: {{status}}"
    },
    "rate_limit": 500,
    "allowed_ips": ["203.0.113.10"]
  }'

⚠️ The api_key is returned only once in the create response. Store it securely — it cannot be retrieved later.

POST /api/v1/external-functions/{uuid}/regenerate-key

Generates a new API key and invalidates the old one. The new key is only returned once.

curl -X POST "https://zapini.app/api/v1/external-functions/{uuid}/regenerate-key" \
  -H "Authorization: Bearer {token}"

Available Action Types

send_messagesend_message — Send a text message
send_buttonssend_buttons — Send a message with buttons
send_mediasend_media — Send media (image, video, document)
create_contactcreate_contact — Create a new contact
update_contactupdate_contact — Update an existing contact
create_leadcreate_lead — Create a Kanban lead
update_leadupdate_lead — Update a Kanban lead
pause_automationpause_automation — Pause AI automation for a conversation
resume_automationresume_automation — Resume AI automation for a conversation

Error Codes

AI_AGENT_NOT_ENABLED403 — AI_AGENT_NOT_ENABLED — No active AI Agent integration
DUPLICATE_SLUG422 — DUPLICATE_SLUG — Slug already exists for this account

Ready to Get Started?

Create your account now and start integrating WhatsApp into your applications with our powerful and easy-to-use API.