Integraatiot
Webhookit
Saat tiedon sekunneissa, kun joku ilmoittautuu, maksaa, saapuu tai poistaa tietonsa, Standard Webhooks -tavalla allekirjoitetussa rungossa, jotta tiedät viestin tulevan meiltä.
Miten ne toimivat
Webhook-päätepiste on oma https-osoitteesi, jota AttendBeacon kutsuu POST-pyynnöllä, kun tapahtumissasi tapahtuu jotain. Lisää päätepiste työtilassa kohdassa Integraatiot › Webhookit tai rajapinnan kautta (POST /webhooks), valitse sen vastaanottamat tapahtumatyypit ja tallenna allekirjoituksen salaisuus, joka näytetään vain kerran.
AttendBeacon kirjoittaa jokaisen tapahtuman ensin tietokantansa jonoon ja kutsuu sitten jokaista kuuntelevaa päätepistettä, joten uudelleenkäynnistys meidän päässämme ei koskaan hukkaa yhtäkään. Jokaisessa kutsussa on sama viestitunniste jokaisella yrityksellä, joten toiston voi tunnistaa.
Tapahtumatyypit
| Tyyppi | Lähetetään, kun | Tilaus vaatii |
|---|---|---|
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 |
Viiteoppaan Webhook-tapahtumat näyttää kunkin tyypin kentät ja esimerkin. GET /webhooks/event-types vastaa samalla luettelolla ja kunkin hyötykuorman JSON-skeemalla koodille, joka haluaa tarkistaa vastaanottamansa tiedot.
Mitä saapuu
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
}
}
}Runko on { type, timestamp, data }. data-kentän osallistujalla on samat kentät kuin rajapinnan palauttamalla osallistujalla, joten toiselle kirjoitettu koodi toimii toisellekin. Hotellimajoituksia, matkoja, kulukorvauksia, vuoroja, todistuksia, sisältöä ja yhteisön jäseniä koskevat tyypit sisältävät vain tunnisteita, tiloja, päivämääriä ja summia, ei koskaan nimeä.
Vastaa millä tahansa 2xx-koodilla 15 sekunnin kuluessa. Tee varsinainen työ jälkikäteen: laita viesti omaan jonoosi ja vastaa heti.
Allekirjoituksen tarkistaminen
Kuka tahansa voi lähettää osoitteeseesi, joten tarkista jokainen kutsu ennen kuin luotat siihen. Allekirjoitus on merkkijonon {webhook-id}.{webhook-timestamp}.{body} Base64-muotoinen HMAC-SHA256 päätepisteesi salaisuudella (osa whsec_-etuliitteen jälkeen, Base64-dekoodattuna), kirjoitettuna muodossa v1, ja allekirjoitus. Kun salaisuutta vaihdetaan, otsakkeessa voi olla kaksi allekirjoitusta välilyönnillä erotettuina; hyväksy kutsu, jos toinen niistä täsmää.
- Tarkista raaka runko täsmälleen sellaisena kuin se saapui, ennen JSON-jäsennystä.
- Hylkää aikaleima, joka poikkeaa kellostasi yli viisi minuuttia, jotta tallennettua kutsua ei voi toistaa myöhemmin.
- Vertaa vakioajassa.
- Muista käsittelemäsi viestitunnisteet ja ohita toistot.
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
}Menetelmä on Standard Webhooks, joten sen kirjastot omalle kielellesi tarkistavat kutsumme sellaisinaan samalla salaisuudella.
Uudelleenyritykset
Kutsua, joka ei saa 2xx-vastausta 15 sekunnin kuluessa, yritetään uudelleen kahdeksan kertaa hieman alle vuorokauden aikana: heti, 10 sekunnin, minuutin, 5 minuutin, 30 minuutin, 2 tunnin, 6 tunnin ja 15 tunnin kuluttua. Jokaista muuta kuin 2xx-vastausta yritetään uudelleen, myös 4xx-vastausta: päätepiste, joka vastaa 401 epäonnistuneen käyttöönoton jälkeen, on yleensä korjattu aamuun mennessä.
Poikkeus on 410 Gone: se kytkee päätepisteen pois, koska vastaanottaja ilmoitti, ettei sitä enää ole. Kytke se takaisin päälle työtilassa, kun se taas on olemassa.
Kunkin päätepisteen sivu työtilassa luettelee sen toimitukset 30 päivän ajalta: mitä lähetettiin, jokainen yritys ja mitä päätepiste vastasi, sekä Lähetä uudelleen epäonnistuneelle. Lähetä testitapahtuma lähettää allekirjoitetun webhook.test-tapahtuman, kun seuraat.
Päätepisteet rajapinnan kautta
webhooks:write-oikeudella avain voi itse lisätä, muuttaa, testata ja poistaa päätepisteitä, mikä sopii ohjelmistolle, joka määrittää omansa: POST /webhooks palauttaa päätepisteen ja sen salaisuuden kerran; POST /webhooks/{webhookId}/secret luo uuden salaisuuden ja lopettaa vanhan toiminnan heti. Työtilalla voi olla enintään 20 päätepistettä.
Automaatioalustat
Power Automate, Zapier ja Make tilaavat sen sijaan kutsulla POST /hooks, yksi tilaus työnkulkua kohden, ja vastaanottavat samat tapahtumat tavallisena JSONina, jossa data on nostettu ylimmälle tasolle: { id, type, timestamp, event, attendee }. Ne eivät tarvitse salaisuutta: niiden antama osoite on itsessään niiden salaisuus. Katso Power Automate ja Zapier.