Skip to content
WrongNotebook
ProductsPersonal BaaSDocumentationQuickstart
Sign inCreate workspace
Browse documentation

Start here

  • Quickstart
  • API keys and scopes

Working with data

  • Collections
  • Records
  • Filtering, sorting and paging
  • Schemas and validation
  • Files

Integrate

  • Webhooks
  • Recipes

Reference

  • Errors
  • Limits and rate limits

Start here

  • Quickstart
  • API keys and scopes

Working with data

  • Collections
  • Records
  • Filtering, sorting and paging
  • Schemas and validation
  • Files

Integrate

  • Webhooks
  • Recipes

Reference

  • Errors
  • Limits and rate limits
  1. WrongNotebook
  2. /
  3. Docs
  4. /
  5. Webhooks

Webhooks

Get an HTTP call when records or collections change, with signed payloads, automatic retries and a delivery log.

A webhook calls your server when something changes, so you can rebuild a site, post to Slack, or sync another system — without polling.

Set one up

Settings → Webhooks → Create webhook. You give it:

  • the URL on your server to call;
  • the events you care about;
  • optionally the collections to watch, or all of them.

You get a signing secret starting whsec_, shown once. Keep it; you need it to check that calls really came from us.

Events

EventWhen
record.createdA record was added
record.updatedA record changed
record.deletedA record was moved to the trash
record.restoredA record came back from the trash
collection.createdA collection was added
collection.updatedA collection's settings changed
collection.deletedA collection was moved to the trash
collection.restoredA collection came back
schema.updatedA schema version was activated or switched off

You can also subscribe to all events, which includes any added later. Imports and bulk writes send one event per record.

What arrives

HTTP
POST /hooks/baas HTTP/1.1
content-type: application/json
x-baas-event: record.created
x-baas-delivery: 9f3c1a7e-…
x-baas-timestamp: 1791406000
x-baas-signature: v1=5d41402abc4b2a76b9719d911017c592…
x-baas-webhook-id: 6b0e…

{
  "id": "0192f0b4-…",
  "type": "record.created",
  "createdAt": "2026-10-10T09:14:02.000Z",
  "workspaceId": "ac3385ca-…",
  "collectionId": "41a46615-…",
  "data": { "record": { "id": "01a12621-…", "data": { "title": "Ship it" } } }
}

Reply with any 2xx as soon as you have the message. Do the slow part afterwards: we give up on a call after 10 seconds and treat it as failed.

Check the signature

Do this before you trust anything in the body. The signature is

"v1=" + hex(HMAC_SHA256(secret, timestamp + "." + raw_body))

where raw_body is the exact bytes you received. Parsing the JSON first and re-serialising it will change the bytes and the check will fail.

JavaScript
// Node / Next.js route handler
import crypto from 'node:crypto';

export async function POST(request) {
  const raw = await request.text(); // raw bytes, before JSON.parse
  const timestamp = request.headers.get('x-baas-timestamp');
  const signature = request.headers.get('x-baas-signature');

  // Reject anything older than five minutes: stops a captured call being replayed.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300)
    return new Response('stale', { status: 400 });

  const expected =
    'v1=' +
    crypto
      .createHmac('sha256', process.env.WEBHOOK_SECRET)
      .update(`${timestamp}.${raw}`)
      .digest('hex');

  const ok =
    signature?.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!ok) return new Response('bad signature', { status: 401 });

  const event = JSON.parse(raw);
  // … your work here …
  return new Response(null, { status: 204 });
}
Python
import hmac, hashlib, time

def verify(secret: str, body: bytes, timestamp: str, signature: str) -> bool:
    if abs(time.time() - int(timestamp)) > 300:
        return False
    mac = hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256)
    return hmac.compare_digest(f"v1={mac.hexdigest()}", signature)

Compare in constant time (timingSafeEqual, compare_digest) rather than with ==.

Delivery is at-least-once

The same event can arrive twice — for instance if your reply was lost on the way back. Use x-baas-delivery, which is the same for every retry of one event, to ignore duplicates:

JavaScript
if (await alreadyHandled(deliveryId)) return new Response(null, { status: 204 });

Retries and failures

A failed call is retried with increasing gaps — 15 seconds, 30 seconds, 1 minute, 2 minutes, and so on up to an hour — for up to 8 attempts. After that the delivery is marked dead.

If 25 deliveries die in a row, the webhook is switched off automatically and the event is recorded in your audit log. Re-enabling it clears the counter. This stops a dead endpoint from being hammered forever.

Every attempt is logged with its status, duration and response, and kept for 30 days. Open the webhook in the dashboard to see them, replay one, or send a test call (webhook.ping) to check your endpoint before going live.

URLs we refuse

Webhook URLs point outward from our servers, so they are restricted to protect both of us: HTTPS in production, no credentials in the URL, no localhost or internal hostnames, and no addresses that resolve to private networks. Redirects are not followed. A URL that breaks these rules is rejected with 400 INVALID_WEBHOOK_URL when you save it.

To develop locally, use a tunnel such as ngrok or Cloudflare Tunnel and register the public URL it gives you.

Rotating the secret

Rotate from the webhook's menu. The new secret applies from the next delivery — there is no overlap — so update your server first, or expect a few failed calls that will be retried.

Next steps

  • Recipes — a webhook that rebuilds a static site.
  • Errors — the error codes.

View this page as Markdown — handy for copying into an editor or an AI assistant.

PreviousFilesNextRecipes

On this page

  • Set one up
  • Events
  • What arrives
  • Check the signature
  • Delivery is at-least-once
  • Retries and failures
  • URLs we refuse
  • Rotating the secret
  • Next steps
WrongNotebook

Personal BaaS is one focused product from WrongNotebook.

Documentation

  • All pages
  • Quickstart
  • Recipes
  • Errors

Product

  • Personal BaaS
  • All products
  • View the demo

Get started

  • Sign in
  • Create workspace

© 2026 WrongNotebook. All rights reserved.