Theme

Guides

Webhooks

Webhooks allow you to receive HTTP callbacks when events occur in your Liveday account. Instead of polling the API, you configure a URL and Liveday will send a POST request to it whenever a subscribed event fires.

All webhook events, payload schemas, and the delivery-inspection endpoints are also documented in the interactive API Reference under the Webhooks tag and the spec's webhooks section.

Getting started

  1. Create an endpoint — an HTTPS URL on your server that accepts POST requests with a JSON body and responds with a 2xx status code.
  2. Register it — in the Integrations section of your Liveday dashboard, create a webhook integration, provide your URL, and select the events to subscribe to.
  3. Acknowledge quickly — return 2xx within 30 seconds. If processing takes longer, acknowledge first and process asynchronously.
  4. Deduplicate — store the X-Webhook-Delivery-ID header value and skip deliveries you have already processed.

Events

EventDescriptionPayload
OrderCompletedFired when an order is successfully completed for your organizationThe complete order object — the same Order model returned by GET /analytics_search/api/transactions (see the API Reference)

Delivery

When an event fires, Liveday sends an HTTP POST request to your configured URL with the event payload as JSON.

Headers

Every webhook request includes these headers:

HeaderDescription
Content-Typeapplication/json
X-Webhook-Delivery-IDUnique ID for this delivery — stable across retries of the same delivery
X-Webhook-Event-TypeThe event type (e.g. OrderCompleted)
X-Webhook-AttemptAttempt number (starts at 1, up to 5)

Example payload (OrderCompleted, abridged)

{
  "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "email": "anna@example.com",
  "phone_number": "+46701234567",
  "total_price": 59800,
  "payment_method": "card",
  "payment_method_brand": "visa",
  "is_refunded": false,
  "order_number": 10042,
  "order_source": "webshop",
  "created_at": "2026-03-01T14:30:00Z",
  "cart": {
    "organization": "your-org-id",
    "event": "evt_summer2026",
    "currency": "SEK",
    "total_price": 59800,
    "original_price": 69800,
    "items": [
      {
        "product_type": "Ticket",
        "name": "General Admission",
        "quantity": 2,
        "price": 29900,
        "vat": 6.0,
        "event": "evt_summer2026",
        "event_name": "Summer Festival 2026",
        "category": "ticket"
      }
    ],
    "campaigns": [
      {
        "uuid": "camp_earlybird",
        "name": "Early Bird",
        "code": "EARLY2026",
        "discount_amount": 10000
      }
    ]
  }
}

The payload is the full Order object and contains more fields than shown here — the complete, always up-to-date schema is in the Webhooks section of the API Reference.

Responding

Your endpoint should return a 2xx status code to acknowledge receipt. Any other status code — or a timeout or connection error — is treated as a failed attempt and triggers a retry.

Respond quickly

Your endpoint must respond within 30 seconds (connection timeout: 5 seconds). If processing takes longer, acknowledge the webhook immediately and process it asynchronously.

Retries and delivery guarantees

AspectBehavior
SuccessAny 2xx response within 30 seconds
FailureNon-2xx response, timeout (30 s total / 5 s connect), or connection error
AttemptsUp to 5 attempts in total (1 initial + up to 4 retries)
Retry timingFailed deliveries are re-queued immediately — a retry typically arrives within seconds of the failed attempt. A nominal exponential backoff schedule (5 s doubling per attempt, capped at 5 minutes, ±15% jitter) is recorded on the delivery record's next_retry_at field, but is not enforced as a wait — do not rely on spacing between attempts
After the 5th failureThe delivery is marked PermanentlyFailed and never retried
OrderingNo ordering guarantee — deliveries are independent messages on a standard queue and can arrive out of order
DuplicatesAt-least-once delivery — in rare cases the same delivery can arrive more than once; deduplicate on X-Webhook-Delivery-ID

Delivery statuses

StatusDescription
PendingQueued for delivery
InProgressCurrently being delivered
SuccessEndpoint returned 2xx
FailedAttempt failed, will retry
PermanentlyFailedAll attempts exhausted

Verifying authenticity

Every delivery is signed. Your signing secret (whsec_…) is generated when the webhook integration is created and is shown on the integration in the Liveday dashboard (and returned by the integrations API).

Each delivery carries two extra headers:

HeaderValue
X-Webhook-TimestampUnix timestamp (seconds) when this attempt was signed
X-Webhook-Signaturev1=<hex> — HMAC-SHA256 of {timestamp}.{raw_body} keyed with your signing secret

To verify:

  1. Reject the request if |now − X-Webhook-Timestamp| exceeds 300 seconds (replay protection).
  2. Compute expected = "v1=" + hex(hmac_sha256(secret, timestamp + "." + raw_body)) over the exact raw request body bytes — verify before parsing, never re-serialize the JSON.
  3. Compare with a constant-time comparison.
import hmac, hashlib, time

def verify_webhook(secret: str, headers: dict, raw_body: bytes, tolerance: int = 300) -> bool:
    ts, sig = headers.get("X-Webhook-Timestamp", ""), headers.get("X-Webhook-Signature", "")
    if not ts or not sig.startswith("v1="):
        return False
    if abs(time.time() - int(ts)) > tolerance:
        return False  # stale — possible replay
    expected = "v1=" + hmac.new(secret.encode(), ts.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)  # constant-time

Retried deliveries are re-signed with a fresh timestamp. Integrations created before signing shipped receive their secret the next time the integration is updated; unsigned deliveries (no signature headers) can still be authenticated by looking up the X-Webhook-Delivery-ID via GET /webhooks/deliveries/{delivery_id}.

Monitoring deliveries

You can monitor webhook delivery status from the Integrations section of your Liveday dashboard, or via the API:

EndpointDescription
GET /webhooks/deliveriesList all webhook deliveries for your organization
GET /webhooks/deliveries/{delivery_id}Fetch a single delivery (status, attempt count, retry schedule)
GET /webhooks/deliveries/{delivery_id}/attemptsList each attempt: HTTP status code, response body (truncated to 5000 characters), duration, and error message

These endpoints currently authenticate with a Liveday dashboard user JWT (not sk_ API keys).

Payload

The OrderCompleted payload is the full Order object as returned by the transactions API — see the Webhooks section of the API Reference for the complete, always up-to-date schema.

Best practices

  • Verify the event type — check the X-Webhook-Event-Type header before processing
  • Use the delivery ID for idempotency — the X-Webhook-Delivery-ID header uniquely identifies each delivery and is stable across its retries; use it to avoid processing duplicates
  • Return 2xx quickly — acknowledge receipt immediately and process asynchronously if needed
  • Don't rely on ordering or retry spacing — retries can arrive within seconds and deliveries can arrive out of order
  • Verify authenticity — deliveries are unsigned; confirm the delivery via the read API before acting on sensitive data
Previous
Explorer