Integrations & API

Webhooks

Real-time notifications to your own server: the events, the payload, verifying the signature, and what happens when delivery fails.

5 min readUpdated 2026-09-30

When someone buys a ticket to your kirtan evening or a gathering of yours goes live, that happens instantly inside BrightStar. A webhook is how your own tools find out just as fast, without anyone logging in to check. Instead of asking BrightStar for news every few minutes, BrightStar sends a message to an address you control the moment it happens. You set the address up once, on Dashboard → Integrations → Webhooks, and BrightStar keeps delivering from then on. It matters most for organizers with an attendee database, a studio system, or an automation tool like Make or n8n that needs to stay in step with what is actually happening. Webhooks are part of Elevate and Amplify, and only the account owner can add them.

Adding an endpoint

About two minutes, once:

  1. 1Open Dashboard → Integrations → Webhooks
  2. 2Paste your HTTPS address and tick the events you want
  3. 3Copy the signing secret straight away — it begins with whsec_ and is shown only once
  4. 4Press Send test: a sample order arrives with livemode set to false

What events can trigger a webhook?

Nine moments are sent. order.created fires when a paid order is final — the one you'll lean on for an attendee spreadsheet or a welcome sequence. attendee.created fires at the same moment for each registered attendee on that order. order.cancelled fires when tickets on an order are voided — by you from the dashboard, when you cancel a gathering or a ticket type, when you approve a refund request, or when a door sale is voided — and says whether the whole order or only some tickets were cancelled. ticket.refunded fires when an order is refunded, within about five minutes. ticket.checked_in fires when a ticket is scanned or checked in by hand at the door, within about five minutes (the door never waits on your server). ticket.transferred fires when a ticket is shared with someone else, with who it went to. event.published fires the first time a gathering goes live, event.updated each time a change to a live gathering is saved (with the fields that changed), and event.cancelled when you cancel a gathering — useful if you mirror your listings on your own site.

Each is sent only for gatherings on Elevate or Amplify; Seva gatherings don't carry integrations. Free orders and door sales are not announced as new orders yet, and cancellations the payment processor makes on its own (a failed payment, a chargeback) are not announced as order.cancelled.

What's inside a webhook payload?

Every webhook is a POST with the same envelope: an id for that delivery (the same on every retry), a type telling you which event it is, created (when it was queued, in Unix seconds), livemode (false only for Send test), and a data object holding the record.

The records are the same ones the Zapier triggers return, so nothing new needs mapping. For order.created that means the buyer's name, email and phone, the gathering (id, name, date and link), the order (id, status, amount, currency, any discount code), the tickets grouped by type with quantity and price, the answers to your questions under your own wording, and a consent block saying whether the buyer agreed to hear from you.

Because your webhook address is public, anything can POST to it — including someone trying to fake an order. Every request carries a BrightStar-Signature header shaped like t=1790726400,v1=5f2b… where v1 is an HMAC-SHA256 of the timestamp, a full stop, and the raw request body, keyed with your signing secret. Recompute it on your side from the raw body, compare in constant time (never a plain string comparison), and reject anything whose timestamp is more than five minutes old — that also stops an old message being replayed. It is the same scheme Stripe uses. For older integrations, an X-BrightStar-Signature header also carries sha256= followed by the HMAC of the raw body alone.
javascript
import crypto from 'crypto'

function verify(secret, header, rawBody) {
  const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')))
  const t = Number(parts.t)
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
  const a = Buffer.from(expected, 'hex'), b = Buffer.from(parts.v1 || '', 'hex')
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

What happens when delivery fails?

Answer with any 2xx status within ten seconds and the delivery is done. If your server is down, slow, or returns an error, BrightStar tries again after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours. After that the delivery is marked dead and shown in the delivery log on the Webhooks tab, where you can retry it once your endpoint is fixed. Redirects are not followed, so give the final address. You can pause an endpoint at any time and resume it later.

Best practices for handling webhooks

A few habits keep webhook handling reliable, especially once you rely on it for attendee data:

  1. 1Verify the signature before you do anything else with the payload
  2. 2Respond with a 200 straight away, then do the real work in the background
  3. 3Use the delivery id to recognise and ignore a message you've already handled
  4. 4Check marketing_consent before adding anyone to a newsletter
  5. 5Only use HTTPS endpoints
  6. 6Keep your signing secret out of your code

Common questions

What events can BrightStar webhooks notify me about?

BrightStar sends order.created when a paid order is final, attendee.created for each attendee on that order, order.cancelled when tickets on an order are voided, ticket.refunded when an order is refunded, ticket.checked_in at the door, ticket.transferred when a ticket is shared, and event.published, event.updated and event.cancelled as a gathering goes live, changes and is cancelled. Each is a POST to the address you add under Integrations → Webhooks.

Read more

You choose the events per endpoint, so a check-in tool can take only attendee.created and ticket.checked_in while an accounting sheet takes order.created, order.cancelled and ticket.refunded. They are sent for Elevate and Amplify gatherings.

How do I verify a webhook actually came from BrightStar?

Read the BrightStar-Signature header (t=…,v1=…). Compute an HMAC-SHA256 of the timestamp, a full stop and the raw body with your signing secret, compare it to v1 in constant time, and reject timestamps more than five minutes old. Reject the request if they don't match.

Read more

Skipping this means your endpoint will trust any POST that reaches its address, including a forged one. The timestamp check stops someone replaying a real message later.

What happens if my webhook endpoint is down when BrightStar tries to deliver?

BrightStar retries after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours. After that the delivery is marked dead in the log, and you can retry it yourself once the endpoint is fixed.

Where can I see whether my BrightStar webhooks are being delivered?

The Webhooks tab under Dashboard → Integrations shows the last 50 deliveries with their status, the HTTP code your server returned, the number of attempts, and a Retry button for anything that failed.

I lost my signing secret. What now?

The secret is shown once and stored encrypted, so it cannot be shown again. Remove the endpoint, add it again to get a new secret, and update your server.

How should I handle duplicate webhook deliveries?

BrightStar never announces the same order, attendee, refund, check-in, transfer, cancellation or publish twice to one endpoint (each saved change to a gathering is its own event.updated), but a retry after a timeout can arrive after your server already handled the first try. Treat the delivery id as a unique key and ignore one you've seen.

Ready to get started?

Create your first event on BrightStar — it’s free.