Webhooks

Webhooks allow ZPBX to push real-time event notifications to your server when something happens — a call completes, a balance drops below a threshold, a number is assigned, etc.

Webhooks are not yet available. This page documents the planned API contract. Join the waitlist or contact support to be notified when webhooks go live.

How webhooks will work

  1. You register a webhook endpoint (a URL on your server) in the ZPBX console.
  2. When an event occurs, ZPBX sends an HTTP POST to your URL with a JSON payload.
  3. Your server responds with 200 OK to acknowledge receipt.
  4. If your server doesn't respond within 10 seconds, ZPBX retries with exponential backoff.

Planned events

EventTriggerPayload
call.completedA call ends and the CDR is finalizedCDR object (uuid, duration, cost, direction, etc.)
balance.lowAccount balance drops below the configured thresholdBalance amount, threshold, billing group
number.assignedA number is assigned to a reseller or sub-resellerNumber, assigned entity, rates
restriction.violationA call was rejected by a whitelist/blacklist ruleCaller ID, destination, rule that matched

Webhook payload format

All webhooks will share this envelope:

{
  "event": "call.completed",
  "timestamp": "2026-07-01T14:30:00Z",
  "data": {
    "uuid": "a1b2c3d4-...",
    "callerId": "+34743071846",
    "destination": "212536685869",
    "duration": 1844,
    "direction": "INBOUND",
    "sellCost": 0.77,
    "hangupCause": "NORMAL_CLEARING"
  }
}

Signature verification (planned)

Each webhook will include an X-ZPBX-Signature header containing an HMAC-SHA256 signature of the raw body, computed using your webhook secret. Verify it on your server to confirm the request came from ZPBX:

import hmac, hashlib

def verify_signature(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Retry policy

AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour

After 5 failed attempts, the webhook is marked as failed and visible in the console.

Next steps