Skip to main content
Webhooks let you receive real-time HTTP POST notifications when events happen in Zeeg. Instead of polling the API, you register a callback URL and Zeeg pushes event data to you the moment something occurs. Zeeg supports three event types:
EventTrigger
invitee.scheduledAn invitee books, or a booking is rescheduled
invitee.cancelledAn invitee or host cancels a booking
routing_form.submittedA visitor submits a routing form

Setting up webhooks

Create a webhook subscription by sending a POST request to /webhooks.

Required fields

FieldTypeDescription
callbackUrlstringThe URL Zeeg will send events to. Must be publicly reachable.
eventsarrayOne or more event types to subscribe to.
scopestringuser or organization.

Optional fields

FieldTypeDescription
tokenstringA secret token included in delivery headers for verification.

Scope explained

  • user — You only receive events related to your own scheduling pages.
  • organization — You receive events for all members of your organization. Requires an API token belonging to an admin or owner.

Example

curl -X POST https://api.zeeg.me/v2/webhooks \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "callbackUrl": "https://example.com/webhooks/zeeg",
    "events": ["invitee.scheduled", "invitee.cancelled"],
    "scope": "organization",
    "token": "my-secret-verification-token"
  }'

Response

{
  "success": true,
  "resource": {
    "uuid": "9a39bf60-a6c3-45e7-80cd-2cd36e520861",
    "name": null,
    "description": null,
    "callbackUrl": "https://example.com/webhooks/zeeg",
    "scope": "organization",
    "creator": {
      "firstName": "Lena",
      "lastName": "Meier",
      "slug": "lena-meier"
    },
    "events": ["invitee.scheduled", "invitee.cancelled"],
    "organization": null,
    "apiVersion": null,
    "createdAt": "2026-04-10T08:30:00.000000Z",
    "updatedAt": "2026-04-10T08:30:00.000000Z"
  }
}

Verifying webhook origin

If you provide a token when creating the webhook subscription, Zeeg sends it in the Token header of every webhook request. Use this value to verify that incoming requests actually come from Zeeg and not a third party.
Python
from flask import Flask, request, abort

WEBHOOK_TOKEN = "my-secret-verification-token"

app = Flask(__name__)

@app.route("/webhooks/zeeg", methods=["POST"])
def handle_webhook():
    token = request.headers.get("Token")
    if token != WEBHOOK_TOKEN:
        abort(403)

    payload = request.json
    # Process the event
    return "", 200

Event payloads

invitee.scheduled / invitee.cancelled

Both event types share the same payload structure. Cancellation-specific and reschedule-specific fields are populated only when relevant.
{
  "event": "invitee.scheduled",
  "eventUri": "https://api.zeeg.me/v2/scheduled-events/zg-O69bac566950c6",
  "inviteeSalutation": "Ms.",
  "inviteeFirstName": "Sophie",
  "inviteeLastName": "Laurent",
  "inviteeName": "Sophie Laurent",
  "inviteeEmail": "sophie.laurent@northwind.io",
  "inviteePhoneNumber": "+49 170 9876543",
  "inviteeTimezone": "Europe/Paris",
  "inviteeNumberOfSeats": 1,
  "teamName": null,
  "hosts": {
    "1": "Lena Meier"
  },
  "hostsDetails": [
    {
      "slug": "lena-meier",
      "firstName": "Lena",
      "lastName": "Meier",
      "email": "lena.meier@horizondigital.de",
      "fullName": "Lena Meier"
    }
  ],
  "title": "30-Minute Discovery Call",
  "duration": 30,
  "durationPretty": "30 mins",
  "type": "ONE_ON_ONE",
  "eventTypeUri": "https://api.zeeg.me/v2/event-types/80f46bf5-eb01-4c07-960e-a9a3e18aae5e",
  "singleUseLink": null,
  "startAt": "2026-04-15T09:00:00+00:00",
  "inviteeStartAt": "2026-04-15T11:00:00+02:00",
  "inviteeStartAtPretty": "11:00 - Wednesday, April 15, 2026",
  "endAt": "2026-04-15T09:30:00+00:00",
  "inviteeEndAt": "2026-04-15T11:30:00+02:00",
  "inviteeEndAtPretty": "11:30 - Wednesday, April 15, 2026",
  "location": "Google Meet",
  "locationLink": "https://meet.google.com/abc-defg-hij",
  "questions": [
    {
      "question": "What would you like to discuss?",
      "answer": "Product demo and pricing options"
    }
  ],
  "questionsAndAnswers": {
    "What would you like to discuss?": "Product demo and pricing options"
  },
  "price": 0,
  "pricePerSeat": 0,
  "currency": null,
  "paymentGateway": null,
  "transactionId": null,
  "guests": ["alex.chen@northwind.io"],
  "eventUuid": "zg-O69bac566950c6",
  "inviteeUuid": "zg-O69bad4047abf0",
  "cancelUrl": "https://zeeg.me/cancel/zg-O69bad4047abf0",
  "rescheduleUrl": "https://zeeg.me/rescheduling/zg-O69bad4047abf0",
  "cancelled": false,
  "cancelledAt": null,
  "cancelledBy": null,
  "cancellationReason": null,
  "rescheduled": false,
  "rescheduledAt": null,
  "rescheduledBy": null,
  "rescheduleReason": null,
  "oldEventUri": null,
  "oldEventUuid": null,
  "oldInviteeUuid": null,
  "oldStartAt": null,
  "oldInviteeStartAt": null,
  "newEventUri": null,
  "newEventUuid": null,
  "newInviteeUuid": null,
  "newStartAt": null,
  "newInviteeStartAt": null,
  "utmCampaign": "spring_launch",
  "utmSource": "linkedin",
  "utmMedium": "social",
  "utmTerm": null,
  "utmContent": null,
  "createdAt": "2026-04-10T08:30:00+00:00"
}

Key fields

FieldDescription
eventUuidUnique event identifier in zg-XXX format. Use this for storage and correlation.
inviteeUuidUnique invitee identifier in zg-XXX format. Use this to track a specific booking across schedule/cancel/reschedule events.
hostsObject mapping host positions to names, e.g. {"1": "Lena Meier"}.
hostsDetailsArray of host objects with slug, firstName, lastName, email, fullName.
inviteeStartAtThe event start time in the invitee’s timezone. Useful for display in confirmation emails or UIs.
cancelled / cancelledAt / cancelledByPopulated when the event is invitee.cancelled. cancelledBy indicates who initiated the cancellation.
rescheduled / rescheduledAt / rescheduleReasonPopulated when a booking is rescheduled.
oldEventUuid / newEventUuidWhen rescheduled, links the old and new events together.
price / currency / paymentGateway / transactionIdPopulated when the booking involves a paid event.
guestsArray of additional guest email addresses added by the invitee.
Store inviteeUuid and eventUuid on your side. These are the best identifiers for correlating bookings, cancellations, and reschedules across webhook deliveries.

routing_form.submitted

{
  "event": "routing_form.submitted",
  "reportId": "71621fb7-30b0-4d91-9f2e-a3e009cc6853",
  "routingFormId": "f1cbafc4-b646-4cf9-af29-193491b555d9",
  "routingFormName": "Inbound Lead Qualification",
  "routingFormSlug": "inbound-lead-qual",
  "routingFormUrl": "https://zeeg.me/RF/inbound-lead-qual",
  "routeType": "EVENT_TYPE",
  "routeCustomUrl": null,
  "headline": null,
  "isFallbackRoute": false,
  "eventType": {
    "id": "80f46bf5-eb01-4c07-960e-a9a3e18aae5e",
    "title": "30-Minute Discovery Call",
    "slug": "30min-discovery-call",
    "uri": "https://api.zeeg.me/v2/event-types/80f46bf5-eb01-4c07-960e-a9a3e18aae5e"
  },
  "answers": [
    {
      "question": "What is your company size?",
      "answer": "50-200 employees",
      "inputId": "f7c82298-6dd9-43bd-98e4-c437b5c0ae47",
      "order": 1
    }
  ],
  "questionsAndAnswers": {
    "What is your company size?": "50-200 employees"
  },
  "createdAt": "2026-04-10T08:30:00+00:00",
  "utmCampaign": "spring_launch",
  "utmSource": "linkedin",
  "utmMedium": null,
  "utmTerm": null,
  "utmContent": null
}

Key fields

FieldDescription
routingFormIdUUID of the routing form.
reportIdUnique identifier for this specific submission.
routeTypeHow the visitor was routed (e.g., EVENT_TYPE).
isFallbackRoutetrue if the default/fallback route was used.
eventTypeThe event type the visitor was routed to (with id, title, slug, uri).
answers / questionsAndAnswersThe visitor’s responses. answers is an ordered array with inputId and order; questionsAndAnswers is a flat key-value map.

Managing webhooks

OperationMethodEndpoint
List webhooksGET/webhooks/scope/{scope}
Get webhook detailsGET/webhooks/{uuid}
Delete webhookDELETE/webhooks/{uuid}
Replace {scope} with user or organization. You can also manage webhooks from the Zeeg dashboard: Account Settings > Webhooks

Auto-deletion

Zeeg automatically deletes a webhook subscription if any of the following conditions are met:
  • DNS cannot be resolved for the callback URL.
  • The callback URL returns a 404 Not Found response.
  • The callback URL returns a 410 Gone response.
When a webhook is auto-deleted, the subscription owner is notified by email. Monitor your inbox to avoid missing events silently.

Best practices

  1. Respond quickly. Return a 2xx status code as fast as possible. Zeeg expects a timely response from your callback URL.
  2. Process asynchronously. Queue the payload for background processing rather than doing heavy work inside the request handler.
  3. Use the verification token. Always set a token when creating a webhook and validate it on every incoming request.
  4. Handle duplicates idempotently. In rare cases, Zeeg may deliver the same event more than once. Use eventUuid or inviteeUuid to deduplicate.
  5. Monitor for auto-deletion emails. If your endpoint goes down and Zeeg deletes the subscription, you will only know through the notification email. Set up alerting on your side.
Last modified on April 4, 2026