Integrasjoner
Webhooks
Få beskjed i løpet av sekunder når noen melder seg på, betaler, kommer inn eller sletter dataene sine, i et innhold signert etter Standard Webhooks, slik at du vet at det var oss.
Slik fungerer de
Et webhook-endepunkt er en https-adresse hos deg som AttendBeacon kaller med en POST når noe skjer på arrangementene dine. Legg til et i arbeidsområdet under Integrasjoner › Webhooks, eller via API-et (POST /webhooks), velg hendelsestypene det skal motta, og ta vare på signeringshemmeligheten som vises én gang.
AttendBeacon skriver hver hendelse til en kø i databasen først, og kaller deretter hvert endepunkt som lytter, så en omstart hos oss mister aldri en hendelse. Hvert kall har med den samme meldings-ID-en ved hvert forsøk, slik at en gjentakelse kan gjenkjennes.
Hendelsestypene
| Type | Sendes når | Abonnement krever |
|---|---|---|
attendee.registered | A registration was created. | attendees:read people:read |
attendee.updated | A registration was changed. | attendees:read people:read |
attendee.cancelled | A registration was cancelled. | attendees:read people:read |
attendee.erased | An attendee deleted their data. | attendees:read |
order.paid | An order was paid. | orders:read people:read |
checkin.created | Somebody was let in. | checkins:read people:read |
feedback.given | A rating was given. | surveys:read people:read |
lead.captured | A lead was captured. | sponsors:read people:read |
certificate.issued | A certificate was issued. | attendees:read |
content.published | Session slides were published. | program:read |
member.joined | Somebody joined a community. | communities:read |
member.left | A member left a community. | communities:read |
stay.requested | A hotel stay was asked for. | events:read |
stay.assigned | A hotel stay was assigned. | events:read |
stay.changed | A hotel stay changed. | events:read |
stay.cancelled | A hotel stay was cancelled. | events:read |
shift.signed_up | A volunteer took a shift. | crew:read |
shift.dropped | A volunteer came off a shift. | crew:read |
travel.changed | A guest's travel changed. | events:read |
claim.submitted | An expense claim was sent in. | finance:read |
claim.approved | An expense claim was approved. | finance:read |
claim.paid | An expense claim was paid. | finance:read |
Webhook-hendelser i referansen viser feltene for hver type og et eksempel. GET /webhooks/event-types svarer med den samme listen og JSON-skjemaet for hvert innhold, for kode som vil kontrollere det den mottar.
Hva som kommer
POST /attendbeacon HTTP/1.1
Host: hooks.example.com
Content-Type: application/json
webhook-id: msg_2f6c1a9e4b7d4c0f8e3a5b9d1c7e0f42
webhook-timestamp: 1792130400
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{
"type": "attendee.registered",
"timestamp": "2026-10-14T12:00:00.000Z",
"data": {
"event": { "eventId": "b3ac0000-0000-4000-8000-000000000001", "slug": "beacon-summit", "name": "Beacon Summit" },
"attendee": {
"attendeeId": "b3ac0008-0000-4000-8000-000000000000",
"ticketTypeName": "Conference pass",
"firstName": "Emma",
"lastName": "Bakker",
"email": "emma.bakker0@example.com",
"status": "active",
"valid": true
}
}
}Innholdet er { type, timestamp, data }. En deltaker i data har de samme feltene som deltakeren API-et svarer med, så kode skrevet for den ene virker for den andre. Typer om hotellopphold, reiser, utleggskrav, vakter, deltakerbevis, innhold og fellesskapsmedlemmer har bare med ID-er, statuser, datoer og beløp, aldri et navn.
Svar med en hvilken som helst 2xx innen 15 sekunder. Gjør arbeidet etterpå: legg meldingen i en egen kø og svar med en gang.
Kontroll av signaturen
Hvem som helst kan sende en POST til adressen din, så kontroller hvert kall før du stoler på det. Signaturen er Base64-kodet HMAC-SHA256 av {webhook-id}.{webhook-timestamp}.{body} med endepunktets hemmelighet (delen etter whsec_, Base64-dekodet), skrevet som v1, og signaturen. Mens en hemmelighet byttes ut, kan headeren inneholde to, atskilt med et mellomrom; godta kallet når én av dem stemmer.
- Kontroller det rå innholdet, nøyaktig slik det kom, før all JSON-parsing.
- Avvis et tidsstempel som avviker mer enn fem minutter fra klokken din, slik at et opptatt kall ikke kan spilles av senere.
- Sammenlign i konstant tid.
- Husk meldings-ID-er du har behandlet, og hopp over en gjentakelse.
import { createHmac, timingSafeEqual } from "node:crypto";
// secret: "whsec_..." as the workspace showed it; body: the raw request body as a string.
export function verify(secret, headers, body) {
const id = headers["webhook-id"];
const timestamp = Number(headers["webhook-timestamp"]);
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key).update(`${id}.${timestamp}.${body}`).digest("base64");
return headers["webhook-signature"].split(" ").some((candidate) => {
const [version, signature] = candidate.split(",");
return version === "v1" && signature.length === expected.length
&& timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
});
}using System.Security.Cryptography;
using System.Text;
// secret: "whsec_..." as the workspace showed it; body: the raw request body as a string.
static bool Verify(string secret, string id, string timestamp, string signatures, string body)
{
if (!long.TryParse(timestamp, out var seconds) || Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - seconds) > 300) return false;
var key = Convert.FromBase64String(secret.StartsWith("whsec_") ? secret[6..] : secret);
var expected = Encoding.ASCII.GetBytes("v1," + Convert.ToBase64String(HMACSHA256.HashData(key, Encoding.UTF8.GetBytes($"{id}.{timestamp}.{body}"))));
return signatures.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Any(candidate => CryptographicOperations.FixedTimeEquals(Encoding.ASCII.GetBytes(candidate), expected));
}import base64, hashlib, hmac, time
# secret: "whsec_..." as the workspace showed it; body: the raw request body as bytes.
def verify(secret: str, headers: dict, body: bytes) -> bool:
msg_id = headers["webhook-id"]
timestamp = headers["webhook-timestamp"]
if abs(time.time() - int(timestamp)) > 300:
return False
key = base64.b64decode(secret.removeprefix("whsec_"))
signed = f"{msg_id}.{timestamp}.".encode() + body
expected = "v1," + base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
return any(hmac.compare_digest(candidate, expected) for candidate in headers["webhook-signature"].split(" "))# $secret: "whsec_..." as the workspace showed it; $body: the raw request body as a string.
function Test-AttendBeaconSignature($secret, $id, $timestamp, $signatures, $body) {
$now = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
if ([math]::Abs($now - [long]$timestamp) -gt 300) { return $false }
$hmac = [System.Security.Cryptography.HMACSHA256]::new([Convert]::FromBase64String($secret -replace '^whsec_', ''))
$hash = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes("$id.$timestamp.$body"))
$expected = [Text.Encoding]::ASCII.GetBytes("v1," + [Convert]::ToBase64String($hash))
foreach ($candidate in $signatures -split ' ') {
if ([System.Security.Cryptography.CryptographicOperations]::FixedTimeEquals([Text.Encoding]::ASCII.GetBytes($candidate), $expected)) { return $true }
}
return $false
}Ordningen er Standard Webhooks, så bibliotekene for ditt språk verifiserer kallene våre som de er, med den samme hemmeligheten.
Nye forsøk
Et kall som ikke svarer 2xx innen 15 sekunder, prøves igjen åtte ganger over litt under et døgn: med en gang, etter 10 sekunder, ett minutt, 5 minutter, 30 minutter, 2 timer, 6 timer og 15 timer. Alle svar utenom 2xx prøves på nytt, også en 4xx: et endepunkt som svarer 401 etter en mislykket utrulling, er som regel rettet innen morgenen.
Unntaket er 410 Gone: det slår av endepunktet, fordi mottakeren har sagt at det ikke lenger finnes. Slå det på igjen i arbeidsområdet når det finnes.
Siden for hvert endepunkt i arbeidsområdet viser leveringene de siste 30 dagene: hva som ble sendt, hvert forsøk og hva endepunktet svarte, med Send på nytt for en som mislyktes. Send testhendelse sender en signert webhook.test mens du ser på.
Endepunkter via API-et
Med webhooks:write kan en nøkkel selv legge til, endre, teste og fjerne endepunkter, som passer for programvare som setter opp sine egne: POST /webhooks svarer med endepunktet og hemmeligheten, én gang; POST /webhooks/{webhookId}/secret lager en ny og stopper den gamle med en gang. Et arbeidsområde kan ha høyst 20 endepunkter.
Automatiseringsplattformer
Power Automate, Zapier og Make abonnerer i stedet via POST /hooks, ett abonnement per flyt, og mottar de samme hendelsene som vanlig JSON med data løftet opp til toppnivået: { id, type, timestamp, event, attendee }. De trenger ingen hemmelighet: adressen de oppgir, er deres egen hemmelighet. Se Power Automate og Zapier.