2026-10-23
· Dylan YuDatabase Webhooks Explained: Trigger Actions When Your Data Changes
A database webhook fires an HTTP request to your own endpoint when a row is created, updated, or deleted. Here's what they're for, how they differ from action buttons, and the practical patterns — notifications, syncs, approvals — that make them worth wiring up.
Here's a problem almost every app hits eventually: something happens in your database, and the rest of your system needs to know about it.
A user signs up — Stripe should be notified, or a welcome email should go out. An order's status flips to paid — the fulfillment service should pick it up. A support ticket is marked resolved — someone's dashboard should update. The classic way to handle this is to write code in the app: after you save the row, call the email service, call the fulfillment API, update the cache. That works, but it has a failure mode you've probably met: the app is the only thing that can trigger those reactions. Every new trigger means editing application code. Every system that needs to know about a change has to be called from the same code path. And the moment a record changes outside the app — a support person edits it in an admin tool, a script imports a batch of rows, someone fixes data directly in the database — nothing fires at all.
Database webhooks exist to solve exactly that: instead of the application deciding when to notify the world, the database event itself does. A webhook is an HTTP request your database (or the tool sitting on top of it) sends to an endpoint you control, whenever a row is created, updated, or deleted. Your API receives the event and does whatever it needs to do — send the email, call the service, update the cache — and it works no matter where the change came from.
This post is a practical look at how database webhooks work, what they're actually good for, and the patterns that are worth wiring up.
What a Database Webhook Actually Is
A webhook is the simplest idea in integration: "when X happens, call this URL." In the database world, X is a data change — a row inserted, updated, or deleted — and the URL is an endpoint on your own server that you write.
The flow looks like this:
Row created/updated/deleted in your database
↓
Webhook fires: POST https://api.your-app.com/webhooks/order-updated
↓
Your endpoint receives the event payload (which row, what changed)
↓
Your code does the follow-up work: email, sync, notify, cache
The payload matters. A good webhook doesn't just say "something changed" — it tells you what: the table, the record ID, the fields that changed, maybe the full row. That's what lets your endpoint act on the event without going back to the database to figure out what happened.
There are two flavors of "call this URL when data changes":
- Database-level webhooks: the database itself (or a trigger/sidecar on it) fires the request. Postgres doesn't do this natively, so you'd use a trigger function, a tool like pgwebhook, or an admin layer that watches for changes.
- Admin-layer webhooks (the kind I build in Basevolt): the panel or tool you use to work with the database fires the request on every insert, update, or delete — including ones you make in the UI, ones an AI agent makes over MCP, and ones imported in a batch. You define "when a row in
ordersis updated andstatusbecomespaid, POST to this endpoint."
The second approach is often the practical one, because it catches every path that touches the data — not just the ones your application code happens to call.
Webhooks vs. Action Buttons: Two Halves of One Idea
If you've looked at database tools lately, you'll see "webhooks" and "action buttons" mentioned together, and it's worth being precise about the difference, because they solve complementary problems.
A webhook is automatic: it fires when data changes, no human involved. Order status becomes paid → endpoint fires → confirmation email goes out. It's for the things that should happen on their own.
An action button is manual: it's a button you place on a row — "Approve Refund", "Mark Shipped" — and when a human clicks it, it fires an HTTP request to your endpoint. The button carries the record's data, so your endpoint knows exactly which order was approved. It's for the things that need a human decision before anything happens.
The two combine into the pattern that actually runs a business: a human clicks "Approve Refund" on an order, the action button calls your refund API, your API updates the row, the webhook on that update fires, and the rest of the system (email, accounting, inventory) reacts. The human made the decision; the machine did everything after it.
What Database Webhooks Are Actually Good For
Let me give you the patterns I've seen work, in rough order of how often they're worth wiring up.
1. Notifications you'd otherwise forget to send
The classic. New row in leads → notify the sales channel. Row in orders becomes paid → send the confirmation email. Ticket becomes resolved → notify the requester. When the notification lives on a webhook instead of inside the application's save path, it can't be skipped by a code path that forgot to call it — and it fires even when the change came from a script, an admin edit, or a direct database fix.
2. Keeping other systems in sync
You have a database that's the source of truth, and another system that needs a copy — a search index, a warehouse, a CRM, a cache. Rather than hoping every write path updates both, you point a webhook at a small sync endpoint that replays the change. It's a poor man's event bus, and for a lot of apps it's all the event bus you need.
3. Approvals and human-in-the-loop workflows
This is the one that's underrated. Webhooks alone are fully automatic — which is wrong for anything that needs a decision. The useful pattern is action button (human decides) + webhook (everything after). An order requests a refund: a button appears on the row, a person clicks "Approve", your API executes the refund, and the webhook on the resulting update notifies accounting and the customer. The machine does the work; the human keeps the judgment call.
4. Audit trails and change feeds
A webhook that logs every change to a changes table (or an external log) gives you a reliable record of what happened, when, and through which path — UI, script, agent, or direct SQL. It's a cheap audit trail, and it doubles as the feed a data pipeline can consume.
What Not to Use Webhooks For
It's just as important to know the limits.
Don't use a webhook for heavy processing. A webhook handler should be fast — receive the event, kick off the work, return 200. If the follow-up takes seconds or needs retries with backoff, hand it to a queue instead of doing it inline.
Don't rely on a webhook as your only copy of an important state change. Webhooks are best-effort delivery over HTTP. The network fails, your endpoint is down, the request times out. A good system treats the webhook as a signal that a change happened, and reconciles from the source of truth when it needs to be sure.
Don't let the webhook be where business rules live. The webhook tells your system what changed; your system decides what to do. When the rule changes — "now we also email finance" — you change the endpoint, not the webhook config.
The Setup Pattern That Works
Here's the setup pattern I'd recommend, and it's the one that maps to how I've wired it in Basevolt — define the event, point it at an endpoint, and keep the payload inspectable.
Step 1 — pick the trigger precisely. "On every update to orders" is too broad; "when orders.status changes to paid" is a trigger that means something. Most tools let you filter on the changed value, and the filter is where the value is.
Step 2 — write a fast endpoint. It should parse the payload, do one small thing, and return 200. If the work is heavy, enqueue it. Keep the endpoint idempotent — the same event may arrive twice, and processing it twice should be harmless.
Step 3 — make the deliveries visible. When something doesn't arrive, you need to know. A delivery log — every request, its status code, its duration — plus a retry button for the failures, turns webhooks from "sometimes it works" into something you can actually operate.
Why This Matters More When AI Is Writing Your App
Here's the part that's new in the last couple of years: if you're building with Claude or Cursor, webhooks are the natural bridge between the app your agent wrote and the business operations around it. The agent can configure the whole wiring — the action button on the row, the webhook on the status change, the endpoint contract — over MCP, the same way it configured your schema. You're not hand-writing the integration layer; you're reviewing what the agent set up, and the panel is where you see it firing in real time.
The deeper point: an app built by an agent tends to have more of its logic in the database (schema, statuses, relations) and less in hand-rolled glue code. That makes event-driven patterns like webhooks a better fit — the database is the single source of truth, and the webhook is how the rest of the world hears about it.
Bottom Line
Database webhooks are a small idea with an outsized payoff: they move "tell the world about this change" out of your application code and onto the data itself. Use them for notifications, syncs, and the automatic half of approval workflows; keep the handlers fast, idempotent, and visible; and pair them with action buttons when a human decision has to come first.
If you want to see the pattern running without writing an endpoint by hand, Basevolt includes webhooks and action buttons with a delivery log and retry on every plan — connect a database, point a webhook at your API, and click a row button to watch the request fire. It's the shortest path I know from "data changed" to "the world reacted."