Overview
Webhook Ingestion
Ironflow provides two ways to receive external webhooks (Stripe, GitHub, etc.) and transform them into native Ironflow events.
How It Works
Ironflow supports two ingress paths:
Path A — Server-managed source (register via Dashboard / CLI / RPC):
Provider → POST {ironflow}/api/v1/webhooks/:provider → Verify → Deduplicate → Emit Event → Trigger Functions- Verification: If a
verify_header+verify_algorithm(hmac-sha256orhmac-sha1) +verify_secretare configured on theWebhookSource, Ironflow validates the HMAC signature withsubtle.ConstantTimeCompare. Hex-encoded signatures only. - Deduplication: Automatic idempotency by reading the top-level
idorevent_idfield from the JSON payload (no header support, no caller override). - Event name: Built server-side as
{event_prefix}.{payload.type}— e.g. anevent_prefixofstripewithpayload.type=payment_intent.succeededproduces the eventstripe.payment_intent.succeeded. The event’ssourcemetadata column is set towebhook. - Execution: The resulting event triggers matching functions.
Path B — SDK-managed webhook (createWebhook + serve()):
Provider → POST {your-app}/.../webhooks/:provider → SDK runs verify() → SDK runs transform() → POST {ironflow}/api/v1/events → Trigger FunctionsThe SDK mounts its handler on any URL path that contains /webhooks/:provider (regex /\/webhooks\/([^/]+)/). Your verify() runs locally; your transform() produces { name, data, idempotencyKey }; the SDK forwards it to Ironflow’s /api/v1/events endpoint. The Quick Start below uses Path B.
Quick Start (Node.js)
1. Define the webhook source:
import { createWebhook } from "@ironflow/node";
const stripeWebhook = createWebhook({ id: "stripe", // Verification logic (HMAC, etc.) verify: (req) => { /* ... */ }, // Transform payload into Ironflow event transform: (payload) => ({ name: `stripe.${payload.type}`, data: payload.data.object, idempotencyKey: payload.id, }),});2. Register with the server:
import { serve } from "@ironflow/node";
export const POST = serve({ webhooks: [stripeWebhook], functions: [myWorkflow],});3. Point your provider URL:
Any path on your app that ends with /webhooks/stripe works — the SDK matches /webhooks/:provider anywhere in the URL. For a Next.js Route Handler at app/api/webhooks/[provider]/route.ts, the URL is https://your-app.com/api/webhooks/stripe.
Registration Models
| Model | Setup | Use Case |
|---|---|---|
| Dashboard | Dashboard → Webhooks → New Source | Add a server-managed source via UI (provider ID, event prefix, optional verify header/algorithm/secret). |
| CLI | ironflow webhook list, ironflow webhook deliveries, ironflow webhook test | List server-managed sources, browse deliveries, and POST a test payload to /api/v1/webhooks/:provider. |
| SDK (Code) | createWebhook({ ... }) + serve({ webhooks }) | Custom verification or payload mapping that lives next to your application code (Path B). |
Monitoring & Audit
Ironflow records every Path A delivery in the webhook_deliveries table and retains rows for 30 days (hardcoded — a background sweep runs hourly). In the Dashboard → Webhooks section, you can:
- Browse all registered webhook sources and create/delete them from the UI.
- Open the Deliveries view to see status (
accepted,deduplicated,rejected,failed), external ID, timestamp, and linked event ID. - Expand a delivery row to inspect raw request headers and body.
Path B deliveries are not written to webhook_deliveries — they emit straight to /api/v1/events, so they appear in the Events stream rather than the Deliveries view.
Idempotency
On Path A, Ironflow deduplicates by the top-level id or event_id field in the payload (composite unique index on (source_id, external_id)). If the payload has neither field, no dedup occurs. On Path B, dedup is whatever idempotencyKey you return from transform().