Webhooks

Subscribe to platform events on your own HTTPS endpoints. Every payload is signed; replay protection is built in.

Anatomy of a delivery

POST /your/endpoint HTTP/1.1
Content-Type: application/json
Bq-Signature: t=1715792949,v1=4f9c1e6...
Bq-Event-Id: whv_01HZ...
Bq-Delivery-Attempt: 1

{
  "id":         "whv_01HZ...",
  "type":       "gift.settled",
  "created_at": "2026-05-15T13:45:11Z",
  "data": {
    "id":          "gft_01HZ...",
    "status":      "settled",
    "amount_cents": 2500,
    ...
  }
}

Verifying the signature

The Bq-Signature header carries a timestamp t and one or more v1 hashes. To verify:

  1. Reject if t is more than 5 minutes from now (replay window).
  2. Compute HMAC-SHA256(secret, t + "." + raw_body).
  3. Compare in constant time against any v1= value in the header.

Our SDKs handle this for you. The raw helper:

// Node
const event = bq.webhooks.constructEvent(
  rawBody,
  req.headers['bq-signature'],
  process.env.BQ_WEBHOOK_SECRET
);
POST /v1/webhooks
Subscribe an endpoint to a set of events. The signing secret is returned ONCE — store it.
FieldTypeDescription
url string required

HTTPS URL on your side.

events array required

List of event names to subscribe to. Use ["*"] for all.

description string optional

Human-readable label.

Example request

curl -X POST https://api.bequest.org/v1/webhooks \
  -H "Authorization: Bearer $BQ_KEY" \
  -d '{
    "url":    "https://app.example.com/webhooks/bequest",
    "events": ["gift.settled", "campaign.contribution"]
  }'

Example response

{
  "id":             "whe_01HZ...",
  "url":            "https://app.example.com/webhooks/bequest",
  "events":         ["gift.settled", "campaign.contribution"],
  "signing_secret": "whsec_AbCdEf...",
  "status":         "active"
}

Returns: The WebhookEndpoint with the one-time-visible signing_secret.

GET /v1/webhooks
List your webhook endpoints.
PATCH /v1/webhooks/{id}
Update events list or disable an endpoint.
FieldTypeDescription
events array optional

New event subscription set.

status string optional

active | disabled

POST /v1/webhooks/{id}/rotate_secret
Rotate the signing secret. The new value is returned once; the old value is revoked after a 24-hour grace.
GET /v1/webhooks/events
List recent webhook deliveries, useful for debugging.
FieldTypeDescription
endpoint_id string optional

Filter to one endpoint.

status string optional

pending|delivered|failed|expired

Retry policy

A non-2xx response triggers an exponential backoff retry: 1m, 5m, 30m, 2h, 12h, then expired. The same event id is sent every time; idempotency is up to you.

Event index