API Reference
Webhooks API
Subscribe to facility events, verify the signature, and route the payload into Slack, Teams, n8n, or your own automation layer.
Subscribe#
Register a callback URL with one or more facility IDs and event types. Each subscription returns a `subscription_id` and a signing secret. Keep the secret private — use it to verify deliveries.
curl -X POST "https://api.cribscore.co/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"facility_id": "fac_01HZ8X9K2D7N3M5P0AYR4FTC2W",
"callback_url": "https://automation.example.com/cribscore",
"events": ["score_change", "license_change", "violation_recorded"]
}'import httpx
response = httpx.post(
"https://api.cribscore.co/v1/webhooks",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"facility_id": "fac_01HZ8X9K2D7N3M5P0AYR4FTC2W",
"callback_url": "https://automation.example.com/cribscore",
"events": ["score_change", "license_change", "violation_recorded"],
},
timeout=30.0,
)
response.raise_for_status()
print(response.json())Delivery shape#
Every delivery is a POST with JSON body `{ event, payload }`. Two headers identify the delivery: `X-CribScore-Signature` (HMAC-SHA256 of the raw body) and `X-CribScore-Event` (event name).
{
"event": "score_change",
"delivery_id": "dlv_01HZ8YK4X3F8B9T5RC2WN6PHJD",
"occurred_at": "2026-05-15T07:42:11Z",
"payload": {
"facility_id": "fac_01HZ8X9K2D7N3M5P0AYR4FTC2W",
"previous_safety_score": 87,
"new_safety_score": 81,
"delta": -6,
"source_url": "https://www.ccld.dss.ca.gov/.../2026-05-14.pdf"
}
}Verify the signature#
Compute `HMAC_SHA256(body, signing_secret)` and compare with the `X-CribScore-Signature` header in constant time. Reject deliveries that fail verification — never trust an unverified payload, especially when fanning out to chat or email.
import crypto from "node:crypto";
const SIGNING_SECRET = process.env.CRIBSCORE_WEBHOOK_SECRET ?? "";
export function verifyCribscoreSignature(rawBody: string, header: string): boolean {
const expected = crypto
.createHmac("sha256", SIGNING_SECRET)
.update(rawBody)
.digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(header.replace(/^sha256=/, ""), "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}import hmac
import hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
received = header.removeprefix("sha256=")
return hmac.compare_digest(expected, received)Starter templates#
Pre-built relays for Slack, Microsoft Teams, email, and n8n — copy a template, drop your signing secret, ship the relay.
- Slack: https://www.cribscore.co/automation/slack-incoming-webhook.json
- Teams: https://www.cribscore.co/automation/teams-webhook.json
- Email relay: https://www.cribscore.co/automation/email-relay.json
- n8n starter: https://www.cribscore.co/automation/n8n-starter.json
Starter templates (copy + paste, signed-payload ready):
- https://www.cribscore.co/automation/slack-incoming-webhook.json
- https://www.cribscore.co/automation/teams-webhook.json
- https://www.cribscore.co/automation/email-relay.json
- https://www.cribscore.co/automation/n8n-starter.jsonEndpoint reference#
/v1/webhooksCreate a webhook subscription for a facility.
| Name | Type | Required | Description |
|---|---|---|---|
| facility_id | string | required | Target facility ULID. |
| callback_url | string | required | HTTPS POST URL. |
| events | string[] | required | Subset of `score_change` | `license_change` | `violation_recorded`. |
curl -X POST "https://api.cribscore.co/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"facility_id": "fac_01HZ8X9K2D7N3M5P0AYR4FTC2W",
"callback_url": "https://automation.example.com/cribscore",
"events": ["score_change", "license_change", "violation_recorded"]
}'{ "subscription_id": "sub_...", "signing_secret": "whsec_..." }/v1/webhooksList subscriptions for your API key.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | integer | optional | 20 | 1-100. |
| offset | integer | optional | 0 | 0+. |
curl -sS "https://api.cribscore.co/v1/webhooks" -H "Authorization: Bearer YOUR_API_KEY"{ "data": [...], "meta": {} }/v1/webhooks/{subscription_id}Cancel a subscription.
| Name | Type | Required | Description |
|---|---|---|---|
| subscription_id | string | required | Subscription ULID. |
curl -X DELETE "https://api.cribscore.co/v1/webhooks/sub_01HZ8YK4X3F8B9T5RC2WN6PHJD" \
-H "Authorization: Bearer YOUR_API_KEY"{ "deleted": true, "subscription_id": "sub_..." }