Webhooks

Receive a signed POST when participants, registrations, speaker submissions, housing, sourcing, contracts, CE credits, exhibitors, leads, prospect invites, booths, or appointments change.

Webhooks are configured per-event. An event organizer creates them from Developers → Web Hooks inside the event's organizer area. Each webhook subscribes to one or more triggers and targets a URL of your choosing.

Triggers

TriggerFires on
participant A participant record is created or modified, including from the public pre-registration endpoint.
registration A participant is materialized — i.e. an order completes and the registration becomes live.
speaker-submission A speaker session, poster, or abstract draft is created or transitions status (submit, accept, decline, withdraw, etc).
block-request A hotel block request (group block) is created or its allocations change.
hotel-reservation An individual hotel reservation is created or its status changes (e.g. pending → confirmed, cancellations).
sourcing-briefA sourcing brief is created or modified.
sourcing-rfp RFP activity changes, including RFPs, recipients, responses, Q&A, and awards. Payloads carry an entity field so partners can filter by subtype.
approval Approval requests are opened, decided, resolved, or cancelled.
contract Contract or milestone activity changes, including draft, sent, signed, cancelled, and milestone updates.
ce-credit-earned A participant becomes eligible for continuing-education credit.
exhibitor-company An exhibitor company is created or updated, including organizer imports, invites, and portal edits.
exhibitor-lead A lead is captured by a paired lead device or self-scan flow.
prospect-invite A prospect invite is sent by an exhibiting company or converts into a participant.
booth A booth is sold at order fulfillment or released back to the market by a cancellation. Payloads carry an action (sold | released) plus the booth number, size in square feet, company id, and order id.
appointment A peer or booth appointment is created, confirmed, or cancelled.
contact.upserted A cross-event Contact's core profile is created or edited (see the note below — Contact webhooks are configured at the client/tenant workspace, not per event).
contact.merged Two Contacts are merged into a single surviving Contact.
contact.split A source is split off a Contact into a new Contact.

Contact webhooks (the contact.* triggers) belong to the cross-event Contacts feature and are managed at the client or tenant workspace under Developers → Web Hooks — separate from the per-event webhooks above. Their payloads carry the changed contactId; fetch the full record from the /v1 Contacts endpoint.

Payload

Deliveries POST a single JSON object to your endpoint. Common fields on every payload:

  • trigger — the trigger name from the table above.
  • action — typically "created" or "updated". Some triggers carry a more specific value (e.g. "allocation-updated" on a block request).
  • clientCode — slug of the owning client.
  • eventCode — code of the event the resource belongs to.
  • deliveredAt — ISO-8601 timestamp of when the dispatcher enqueued the delivery.
  • One resource id field: participantId, submissionId, blockRequestId, briefId, rfpId, approvalId, contractId, companyId, leadId, inviteId, boothId, appointmentId, or reservationId — depending on the trigger.

Example — participant updated

{
  "trigger": "participant",
  "action": "updated",
  "clientCode": "acme",
  "eventCode": "acme-2026",
  "participantId": "65ec1234abcd5678ef901234",
  "deliveredAt": "2026-05-20T15:30:00.000Z"
}

The payload intentionally carries only the resource id, not the full document. Fetch the entity via the matching /v1 read endpoint using your bearer token to get current state — that way responses reflect the latest data even if you process the webhook minutes after delivery, and PII fields are gated by your token's account flag.

Headers

  • X-Jade-Signaturesha256=<hex>. HMAC-SHA256 of the raw request body using your webhook's signing secret. Verify on every request.
  • X-Jade-Webhook-Id — the webhook configuration that produced this delivery. Useful when one endpoint subscribes to multiple events.
  • X-Jade-Delivery-Attempt — 1 for the first try, 2..5 for retries. Treat anything > 1 as a possible duplicate.
  • User-AgentJade-Webhooks/1.0

Verifying the signature

Compute HMAC-SHA256 over the raw request body (exact bytes, no JSON re-stringification) using the signing secret revealed at webhook creation time, and constant-time-compare against the value after the sha256= prefix.

Node.js

import { createHmac, timingSafeEqual } from 'crypto';

function verify(rawBody, header, secret) {
  const expected = 'sha256=' + createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');
  return expected.length === header.length &&
    timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Python

import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Retry policy

A delivery is considered successful when your endpoint returns a 2xx status within 10 seconds. Anything else — non-2xx, timeout, DNS failure, connection reset — is a failure and triggers a retry.

  • Up to 5 attempts total per delivery.
  • Backoff schedule (seconds between attempts): 10, 30, 60, 300, 900 — roughly a 25-minute budget.
  • After 5 failures the delivery is dropped. The webhook's lastDeliveryStatus in the admin UI shows failed with the most recent error message.
  • Retries reuse the original payload (same body, same signature) so re-running a failed delivery is safe to verify.

Idempotency on your side

We deliver at-least-once. The same logical event can arrive more than once — either because a 2xx response was lost in transit, or because a retry succeeded but you'd already processed an earlier attempt. Recommended:

  • Treat { trigger, eventCode, <resource-id>, action } as a dedup key.
  • Re-fetch the resource from /v1 before applying side effects — payloads carry intent, not state.

Local testing

Pointing webhooks at localhost in dev is fine — Jade does not require HTTPS in non-production environments. For testing from a browser-only setup, services like webhook.site or a tunneled local server (ngrok) work; just verify the signature with the secret shown at creation.