Hopp til hovedinnhold

Webhooks

Webhooks lar en kirke skyve sanntidsmeldinger til tredjeparts verktøy -- automasjonsplattformer (Zapier, Make, n8n), CRM-er, regnskapssystemer eller hva som helst som tar imot en HTTP POST. Når en person, gruppe eller husstand endres i B1, sender B1 en signert JSON-last til hver URL som er abonnert på den hendelsen.

Før du begynner

  • En kirkeadmin med tillatelsen Rediger kirkekonstruksjoner registrerer og administrerer webhooks
  • Mottakersluttpunktet ditt må være nåbart over HTTPS på en offentlig adresse
  • Ha en måte å lagre signeringshemmeligheten på sikkert -- den vises bare en gang

Oversikt

Webhooks er kun utgående: B1 kaller sluttpunktet ditt, du kaller ikke B1. Hver webhook er et per-kirke abonnement som består av en destinasjons-URL, en signeringshemmelighet og en liste over abonnerte hendelser.

Levering bruker en holdbar utboks: når en abonnert hendelse oppstår, registrerer B1 en leveringsrad og en bakgrunnsarbeider POSTer den innen omtrent ett minutt. Mislykkede leveringer blir forsøkt på nytt med eksponensiell backoff. Ingenting går tapt hvis en levering er langsom eller sluttpunktet ditt er kortvarig nede.

Registrering av en webhook

I B1Admin

Gå til Innstillinger → Webhooks → Ny Webhook. Skriv inn et navn, nyttelast-URL og velg hendelsene du vil abonnere på. Ved lagring vises signeringshemmeligheten en gang -- kopier den umiddelbart og lagre den med integrasjonen. Den vises aldri igjen (du kan rotere den senere, men du kan ikke hente originalen).

Via API-en

Alle sluttpunkter er under medlemskapsmodulens basisvei /membership/webhooks og krever enten en JWT fra en kirkeadmin med tillatelsen Innstillinger / Rediger, eller en API-nøkkel preget med settings:write-omfanget. De samme rutene aksepterer begge. Dette er det som gjør at Zapier og Make kan registrere webhooks på kirkens vegne når en Zap eller scenario slås på.

POST /membership/webhooks
Authorization: Bearer <jwt>
Content-Type: application/json

{
"name": "Zapier — nye medlemmer",
"url": "https://hooks.zapier.com/hooks/catch/123/abc",
"events": ["person.created", "person.updated", "group.member.added"]
}

Opprettelsesresponsen -- og bare opprettelsesresponsen -- inkluderer secret:

{
"id": "a1b2c3d4e5f",
"name": "Zapier — nye medlemmer",
"url": "https://hooks.zapier.com/hooks/catch/123/abc",
"events": ["person.created", "person.updated", "group.member.added"],
"active": true,
"secret": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822c"
}
Metode og veiFormål
GET /membership/webhooksVis kirkens webhooks (hemmelighet utelatt)
GET /membership/webhooks/eventsKatalogen over gyldige hendelsesnavn
GET /membership/webhooks/:idLast en webhook
POST /membership/webhooksOpprett (ingen id) eller oppdater (med id)
POST /membership/webhooks/:id/regenerate-secretRoter signeringshemmeligheten; returnerer den nye verdien en gang
DELETE /membership/webhooks/:idSlett en webhook
GET /membership/webhooks/:id/deliveriesNylige leveringsforsøk for en webhook
GET /membership/webhooks/deliveries/:deliveryIdFull last og respons for en levering
POST /membership/webhooks/deliveries/:deliveryId/redeliverOmstill en levering

Hendelsesk katalog

Hendelsenavnet følger mønsteret {entity}.{action}. Hent den aktuelle listen fra GET /membership/webhooks/events.

HendelseUtløses når
person.createdEn person blir lagt til
person.updatedEn personpost er endret
person.destroyedEn person blir slettet
household.createdEn husstand blir lagt til
household.updatedEn husstand blir endret
household.destroyedEn husstand blir slettet
group.createdEn gruppe blir lagt til
group.updatedEn gruppe blir endret
group.destroyedEn gruppe blir slettet
group.member.addedEn person blir lagt til en gruppe
group.member.removedEn person blir fjernet fra en gruppe
donation.createdEn gave blir registrert -- manuell oppføring, nettbasert eller ventende → fullstending overgang
donation.updatedEn donasjonpost blir redigert
attendance.recordedEt besøk blir logget (manuell oppføring eller sjekk-inn)
session.createdEn ny frammøtesesjon blir opprettet (manuelt eller auto ved første sjekk-inn)
form.submission.createdEt skjema blir sendt
event.createdEn kalenderhendelse blir lagt til
event.updatedEn kalenderhendelse blir redigert
event.destroyedEn kalenderhendelse blir slettet

Lastnytteformat

Hver levering er en HTTP POST med en JSON-kropp og disse hodene:

HodeBeskrivelse
Content-TypeAlltid application/json
X-B1-EventHendelsenavnet, f.eks. person.created
X-B1-Delivery-IdUnik id for dette leveringsforsøket -- bruk det til deduplicering
X-B1-SignatureHMAC-SHA256 signatur av raw body (se nedenfor)
X-B1-TimestampUnix epoch sekunder når forespørselen ble sendt
User-AgentB1-Webhooks/1.0

Kroppen pakker den endrede ressursen i en liten konvolutt:

{
"event": "person.created",
"churchId": "AbC123XyZ90",
"occurredAt": "2026-05-17T14:32:08.114Z",
"data": {
"id": "Pq7Rs2Tu4Vw",
"churchId": "AbC123XyZ90",
"name": { "display": "Jordan Rivera", "first": "Jordan", "last": "Rivera" },
"contactInfo": { "email": "jordan@example.com" }
}
}

For *.destroyed-hendelser inneholder data bare id og churchId for den slettede posten.

Koblingstyper

Standardleveringsformatet er JSON-konvolutten ovenfor -- connectorType: "standard". For Slack og Discord poster webhook-motoren i stedet en chat-formet melding som disse tjenestene godtar direkte:

connectorTypeKropp sendtBruk når
"standard" (standard){event, churchId, occurredAt, data} konvolutt, signertDu skriver din egen integrasjon, eller peker på Zapier / Make / en egendefinert server
"slack"{ "text": "💝 Ny donasjon: $50.00" }Du poster direkte til en Slack Incoming Webhook URL
"discord"{ "content": "💝 Ny donasjon: $50.00" }Du poster direkte til en Discord kanal-webhook URL

Koblingstypen angis i rullegardinmenyen Koblingtype på webhook-editoren, eller via connectorType i POST /membership/webhooks-kroppen. Det signerte X-B1-Signature-hodet sendes fortsatt for Slack/Discord-leveringer (de ignorerer det harmløst), så hvis du bytter webhook tilbake til standard senere kreves ingen signering på nytt.

Testleveringer

Hver webhook-editor har en Send testegenskap-knapp -- det tilsvarende API-kallet er POST /membership/webhooks/:id/test. Testruten bygger en syntetisk last for den første abonnerte hendelsen, dispatcher den synkront gjennom den virkelige signerte leveringsbanen (og gjennom formatForConnector for Slack/Discord) og returnerer den resulterende leveringsraden inkludert responseStatus og responseBody. Bruk den til å bekrefte tilkoblinger og signaturhåndtering før du slår integrasjonen på for reelt.

Verifisering av signaturer

Bekreft alltid X-B1-Signature før du stoler på en last. Signaturen er sha256= fulgt av den hex HMAC-SHA256 av den raw request body tastet med signeringshemmeligheten din. Beregn det over bytene du mottok -- ikke serieller JSON på nytt.

Node.js

const crypto = require("crypto");

function isValid(rawBody, signatureHeader, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Python

import hashlib, hmac

def is_valid(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header or "")

PHP

function isValid(string $rawBody, string $signatureHeader, string $secret): bool {
$expected = "sha256=" . hash_hmac("sha256", $rawBody, $secret);
return hash_equals($expected, $signatureHeader ?? "");
}

Avvis enhver forespørsel hvis signaturen ikke samsvarer. Du kan også eventuelt avvise forespørsler hvis X-B1-Timestamp er mer enn et par minutter gammel for å begrense gjenskrift av vinduer.

SDK-støtte

For Node.js leverer @churchapps/integration-sdk en typet bekrefter og en Express-melding som håndterer raw-body-oppdageringen, signaturkontroll og konvolutteanalyse for deg:

import express from "express";
import { b1WebhookMiddleware } from "@churchapps/integration-sdk";

const app = express();
// Fang raw body før JSON-analyse -- nødvendig slik at signaturen fortsatt bekrefter seg selv.
app.use(express.json({ verify: (req, _res, buf) => { (req as any).rawBody = buf; } }));

app.post("/webhooks/b1", b1WebhookMiddleware({ secret: process.env.B1_WEBHOOK_SECRET! }), (req, res) => {
const env = req.b1Webhook!;
switch (env.event) {
case "donation.created": console.log("new gift", env.data.amount); break;
}
res.sendStatus(200);
});

SDK-en eksponerer også WebhookVerifier.verify(secret, rawBody, signatureHeader) for ikke-Express-kjøretider (serverløse funksjoner, Fastify, osv.). Se pakken på npm.

Levering og omforsøk

Sluttpunktet ditt bør svare med en 2xx-status så raskt som mulig -- helst etter bare å ha stilt arbeidet i kø, ikke etter å ha behandlet det. Enhver ikke-2xx-respons, tilkoblingsfeil eller respons som er sakte enn 10 sekunder regnes som en mislykket levering.

Mislykkede leveringer blir forsøkt på nytt med eksponensiell backoff -- 16 forsøk over omtrent 5 dager. Intervallet vokser fra 1 minutt, gjennom timer, opp til 3-dagers avstander for de siste forsøkene. Etter det 16. mislykkede forsøket blir leveringen merket exhausted og oppgitt.

Levering er minst-en gang: en levering kan komme mer enn en gang (for eksempel hvis sluttpunktet ditt lykkes men responsen er tapt). Bruk X-B1-Delivery-Id-hodet til deduplicering -- behandle hver id bare en gang og behandle repetisjoner som no-ops.

Auto-deaktivering

Hvis en webhook produserer tre påfølgende utslittete leveringer, deaktiverer B1 den automatisk. Rett sluttpunktet, og reaktiver deretter webhook i B1Admin (eller via POST /membership/webhooks med "active": true).

Inspeksjon og omleveringer

Webhook-editoren i B1Admin viser en Nylige leveringer-tabell -- hendelse, status, forsøkstall, svarskode og tidsstempel. Hvis du velger en rad vises den fullstendige lasten som ble sendt og svaret som kom tilbake.

Bruk Omlevering til å omsignalere enhver tidligere levering med dens opprinnelige last -- nyttig etter å ha fikset en feil i sluttpunktet ditt, eller for å fylle ut hendelser som sluttpunktet ditt gikk glipp av mens det var nede.

URL-krav

Fordi webhook-URLer leveres av kirken, håndhever B1 vakter mot server-side request forgery. En webhook-URL blir avvist -- ved registrering og sjekket på nytt før hver levering -- hvis den:

  • bruker ikke https
  • peker på localhost, et .local / .internal vertsnavn, eller
  • løses til en privat, loopback, link-lokal eller cloud-metadata IP-adresse

Sluttpunktet ditt må være en offentlig nåbar HTTPS-tjeneste.