Skip to main content
When you configure a webhook, Zenzap sends HTTP POST requests to your URL when events occur. This page documents the payload structure for each event type.

Event Envelope

All webhook events share the same envelope structure:
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.created",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": { ... }
}
FieldTypeDescription
idstringUnique event ID (use for deduplication)
typestringEvent type (see below)
eventVersionintegerSchema version (currently 1)
timestampintegerUnix timestamp in milliseconds
dataobjectEvent-specific payload

HTTP Headers

Each webhook delivery includes these headers:
HeaderDescription
X-Zenzap-EventEvent type (e.g., message.created)
X-Zenzap-SignatureHMAC-SHA256 signature for verification
X-Zenzap-TimestampUnix timestamp (milliseconds) when sent
X-Zenzap-Delivery-IdUnique delivery ID (for deduplication)

Signature Verification

When a secret is configured, verify webhooks by calculating:
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        f"{timestamp}.{payload.decode()}".encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Message Events

message.created

Sent when a new message is posted in a topic where your bot is a member.
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.created",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "message": {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "topicId": "550e8400-e29b-41d4-a716-446655440000",
      "senderId": "u@550e8400-e29b-41d4-a716-446655440001",
      "senderName": "Alice Johnson",
      "senderType": "user",
      "type": "text",
      "text": "Hello team!",
      "createdAt": 1699564800000
    }
  }
}

message.updated

Sent when a message is edited or when voice message transcription completes.
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.updated",
  "eventVersion": 1,
  "timestamp": 1699564850000,
  "data": {
    "message": {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "topicId": "550e8400-e29b-41d4-a716-446655440000",
      "senderId": "u@550e8400-e29b-41d4-a716-446655440001",
      "senderName": "Alice Johnson",
      "senderType": "user",
      "type": "text",
      "text": "Hello team! (edited)",
      "createdAt": 1699564800000,
      "updatedAt": 1699564850000
    }
  }
}

message.deleted

Sent when a message is deleted.
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.deleted",
  "eventVersion": 1,
  "timestamp": 1699564900000,
  "data": {
    "messageId": "660e8400-e29b-41d4-a716-446655440001",
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "deletedBy": "u@550e8400-e29b-41d4-a716-446655440001"
  }
}

Message Object

The message object in message events contains:
FieldTypeDescription
idstringMessage UUID
topicIdstringTopic UUID
senderIdstringSender ID (format: u@{uuid} for users, b@{uuid} for bots)
senderNamestringSender’s display name
senderTypestringuser, bot, or system
typestringMessage type (see below)
textstringMessage text (may be empty for non-text types)
createdAtintegerCreation timestamp (ms)
updatedAtintegerLast update timestamp (ms)
parentIdstringReplied-to message ID
attachmentsarrayFile attachments
mentionsarrayUser mentions
locationobjectLocation data (for location messages)
taskobjectTask data (for task messages)
contactobjectContact data (for contact messages)

Message Types

TypeDescriptionAdditional Fields
textRegular text messagetext
imageImage attachmentattachments[]
fileFile attachmentattachments[]
videoVideo attachmentattachments[]
audioVoice messageattachments[] (with transcription)
locationShared locationlocation
taskTask snapshottask
contactShared contactcontact

Attachments

File attachments include a signed download URL:
{
  "attachments": [
    {
      "id": "att_550e8400-e29b-41d4-a716-446655440088",
      "type": "image",
      "name": "screenshot.png",
      "url": "https://storage.zenzap.co/attachments/...?token=...&expires=..."
    }
  ]
}
Attachment URLs expire after 60 minutes. Download files promptly after receiving the webhook.

Voice Message Transcription

Voice messages (audio attachments) are automatically transcribed. The flow is:
  1. message.created arrives with transcription.status: "Pending"
  2. message.updated arrives when transcription completes
{
  "type": "message.updated",
  "data": {
    "message": {
      "type": "audio",
      "attachments": [
        {
          "id": "att_...",
          "type": "audio",
          "name": "voice-note.mp3",
          "url": "https://storage.zenzap.co/...",
          "transcription": {
            "status": "Done",
            "text": "Hey team, just a quick update on the project..."
          }
        }
      ]
    }
  }
}
Transcription Status Values:
StatusDescription
PendingQueued for transcription
StartedTranscription in progress
DoneComplete - text field populated
FailedTranscription failed

Reply Messages

Messages that reply to other messages include:
{
  "message": {
    "id": "msg_new",
    "text": "I agree!",
    "parentId": "msg_original"
  }
}

Location Messages

{
  "message": {
    "type": "location",
    "text": "",
    "location": {
      "latitude": "37.7749",
      "longitude": "-122.4194",
      "name": "San Francisco Office",
      "address": "123 Market St, San Francisco, CA"
    }
  }
}
address is optional and is included only when available.

Task Messages

Task snapshots are sent when tasks are created, updated, or their status changes:
{
  "message": {
    "type": "task",
    "text": "",
    "task": {
      "id": "task_...",
      "action": "Added",
      "title": "Review documentation",
      "text": "Please review the API docs by Friday",
      "status": "Open",
      "assignee": "u@550e8400-e29b-41d4-a716-446655440001",
      "dueDate": 1699651200000,
      "isDueDateTimeSelected": true,
      "parentId": null,
      "subItemsCount": 0
    }
  }
}
Task Actions:
ActionDescription
AddedTask created
UpdatedTask details changed
DeletedTask removed
MarkedAsDoneTask completed
MarkedAsOpenedTask reopened
RepliedComment added to task

Contact Messages

{
  "message": {
    "type": "contact",
    "text": "",
    "contact": {
      "name": "John Doe",
      "phoneNumbers": ["+1234567890"],
      "emails": ["john@example.com"],
      "role": "Engineer",
      "location": "San Francisco",
      "linkedIn": "https://linkedin.com/in/johndoe",
      "profileId": "u@550e8400-e29b-41d4-a716-446655440001"
    }
  }
}

Reaction Events

reaction.added

{
  "id": "evt_...",
  "type": "reaction.added",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "messageId": "660e8400-e29b-41d4-a716-446655440001",
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "emoji": "👍",
    "userId": "u@550e8400-e29b-41d4-a716-446655440001",
    "userName": "Alice Johnson"
  }
}

reaction.removed

Same structure as reaction.added.

Member Events

member.added

{
  "id": "evt_...",
  "type": "member.added",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "memberId": "u@550e8400-e29b-41d4-a716-446655440003",
    "memberName": "Carol Williams",
    "addedBy": "u@550e8400-e29b-41d4-a716-446655440001"
  }
}

member.removed

{
  "id": "evt_...",
  "type": "member.removed",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "memberId": "u@550e8400-e29b-41d4-a716-446655440003",
    "memberName": "Carol Williams",
    "removedBy": "u@550e8400-e29b-41d4-a716-446655440001"
  }
}

Topic Events

topic.updated

Sent when a topic’s name or description is changed.
{
  "id": "evt_...",
  "type": "topic.updated",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Project Updates - Q4",
    "updatedBy": "u@550e8400-e29b-41d4-a716-446655440001"
  }
}
Only changed fields are included in the payload. If only the description was updated, name would be absent.

Retry & Auto-Pause Behavior

  • Webhooks are retried up to 3 times with exponential backoff on failure
  • After 10 consecutive failures, the webhook is automatically paused
  • Re-enable a paused webhook via the Update webhook configuration endpoint