Integrationer
Webhooks
Få besked inom några sekunder när någon anmäler sig, betalar, kommer in eller raderar sina uppgifter, i en brödtext signerad enligt Standard Webhooks så att du vet att det kom från oss.
Hur de fungerar
En webhook-slutpunkt är en https-adress hos dig som AttendBeacon anropar med en POST när något händer vid dina evenemang. Lägg till en i arbetsytan under Integrationer › Webhooks, eller via API:t (POST /webhooks), välj vilka händelsetyper den ska ta emot, och spara signeringshemligheten som visas en gång.
AttendBeacon skriver först varje händelse till en kö i sin databas och anropar sedan varje slutpunkt som lyssnar, så en omstart hos oss gör aldrig att en händelse går förlorad. Varje anrop har samma meddelande-id vid varje försök, så att en upprepning kan kännas igen.
Händelsetyperna
| Typ | Skickas när | Prenumeration kräver |
|---|---|---|
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-händelser i referensen visar varje typs fält och ett exempel. GET /webhooks/event-types svarar med samma lista och varje innehålls JSON-schema, för kod som vill kontrollera det den tar emot.
Vad som kommer fram
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
}
}
}Brödtexten är { type, timestamp, data }. En deltagare i data har samma fält som den deltagare som API:t svarar med, så kod som skrivits för det ena fungerar för det andra. Typer som gäller hotellvistelser, resor, utläggsräkningar, pass, intyg, material och gemenskapsmedlemmar har bara id:n, statusar, datum och belopp, aldrig ett namn.
Svara med valfri 2xx inom 15 sekunder. Gör arbetet efteråt: lägg meddelandet i en egen kö och svara direkt.
Kontrollera signaturen
Vem som helst kan skicka till din adress, så kontrollera varje anrop innan du litar på det. Signaturen är Base64-kodad HMAC-SHA256 av {webhook-id}.{webhook-timestamp}.{body} med din slutpunkts hemlighet (delen efter whsec_, Base64-avkodad), skriven som v1, följt av signaturen. Medan en hemlighet byts ut kan huvudet innehålla två, åtskilda av ett mellanslag; godta anropet när en av dem stämmer.
- Kontrollera den råa brödtexten, exakt som den kom, före all JSON-tolkning.
- Avvisa en tidsstämpel som avviker mer än fem minuter från din klocka, så att ett inspelat anrop inte kan spelas upp senare.
- Jämför i konstant tid.
- Kom ihåg meddelande-id:n som du har hanterat, och hoppa över en upprepning.
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
}Schemat är Standard Webhooks, så dess bibliotek för ditt språk verifierar våra anrop som de är, med samma hemlighet.
Nya försök
Ett anrop som inte svarar 2xx inom 15 sekunder görs om, åtta gånger under knappt ett dygn: direkt, efter 10 sekunder, en minut, 5 minuter, 30 minuter, 2 timmar, 6 timmar och 15 timmar. Alla svar utom 2xx leder till ett nytt försök, även en 4xx: en slutpunkt som svarar 401 efter en misslyckad driftsättning är oftast lagad till morgonen.
Undantaget är 410 Gone: det stänger av slutpunkten, eftersom mottagaren har sagt att den inte längre finns. Slå på den igen i arbetsytan när den finns.
Varje slutpunkts sida i arbetsytan listar dess leveranser i 30 dagar: vad som skickades, varje försök och vad slutpunkten svarade, med Skicka igen för en leverans som misslyckades. Skicka testhändelse skickar en signerad webhook.test medan du tittar.
Slutpunkter via API:t
Med webhooks:write kan en nyckel själv lägga till, ändra, testa och ta bort slutpunkter, vilket passar programvara som konfigurerar sina egna: POST /webhooks svarar med slutpunkten och dess hemlighet, en gång; POST /webhooks/{webhookId}/secret skapar en ny och stoppar den gamla direkt. En arbetsyta har högst 20 slutpunkter.
Automatiseringsplattformar
Power Automate, Zapier och Make prenumererar i stället via POST /hooks, en prenumeration per flöde, och tar emot samma händelser som vanlig JSON med data upplyft till toppnivån: { id, type, timestamp, event, attendee }. De behöver ingen hemlighet: adressen de anger är deras egen hemlighet. Se Power Automate och Zapier.