Webhook Actions by Flow Systems
Most WordPress integrations are glue code. A wp_remote_post() here, a custom plugin there, an Action Scheduler job nobody else on the team understands. Webhook Actions by Flow Systems replaces that pile with a single, configurable event layer — so you can ship integrations at the pace the rest of your stack moves.
Any do_action becomes a first-class API event: queued, retried, logged, replayable, and reachable over a token-authenticated REST API. The WooCommerce-to-HubSpot round-trip that used to be a two-week project is now an afternoon of configuration. The «can n8n pick this up?» question gets a yes before the meeting ends.
- Build multi-step automations natively, no Zapier required. New in 1.13.0 — Webhook Chains. A webhook completing successfully (2xx) can now trigger downstream webhooks, each receiving the upstream response, sent payload, and pre-mapping original payload as their starting
args. Wire a WooCommerce order → HubSpot deal → HubSpot line items → contact-to-deal association sequence inside one plugin, with every hop fully logged, retried, conditional, and replayable. - Ship full CRM and SaaS integrations in an afternoon. Two webhooks and a dynamic URL template (
https://api.hubapi.com/crm/objects/2026-03/deals/{{ _hs_deal_id }}) turn a WooCommerce order lifecycle into a HubSpot deal lifecycle. Same pattern for Pipedrive, Notion, Airtable, internal services — any REST API that puts ids in the URL path. (Pro) for the{{ }}template syntax, or use thefswa_webhook_urlfilter on the free plan to rewrite the URL from PHP. - Speak n8n, Make, Zapier, and AI-agent fluent. Send any WordPress event into n8n; pull a Claude Code or Cursor agent into your wp-admin via scoped API tokens and let it inspect logs, retry deliveries, and toggle integrations during deploys — without ever touching WordPress credentials.
- Operate WordPress like a real backend. Every event has a UUID, a full request/response log, a replay button, and an HTTP-addressable REST endpoint. Conditional dispatch, custom headers, query parameters, all five HTTP methods, dynamic URL templates — match exactly what each external API expects.
- Replace expensive automation subscriptions with code you own. Move the Zapier/Make tasks that bill per-run back into WordPress. Same triggers, same destinations, no per-zap pricing, no third-party data hop.
- Let the rest of the team ship without asking for help. Junior devs and ops folks configure webhooks in the admin panel. Filters and a (Pro) Code Glue snippet system are there when something custom is genuinely needed. The integrations stay readable, observable, and yours.
Backed by a dedicated persistent queue with intelligent retry and exponential backoff — the queue lives in your database, under your control. Action Scheduler is auto-detected as the optional trigger (the same job runner WooCommerce uses for production stores) and gracefully falls back to WP-Cron when it isn’t available. Same plugin scales from a Contact Form 7 lead form to a high-traffic Black Friday store without changing a line.
The integration architect’s toolkit
You already think in events, payloads, idempotency, and observability. Webhook Actions by Flow Systems is the kit that matches: a persistent queue, a full delivery log, replay, scoped REST API tokens, an extensible filter and action surface (fswa_webhook_payload, fswa_webhook_url, fswa_glue_post_dispatch and more), and an event surface AI agents can safely talk to. Plug it in, and the WordPress side of your stack starts to look like the rest of it.
👉 Step-by-step example: Send Contact Form 7 submissions to a webhook (n8n demo) 👉 Step-by-step example: Send Gravity Forms Submissions to n8n 👉 Step-by-step example: Send IvyForms submissions to a webhook (n8n demo) 👉 Step-by-step example: Send WooCommerce orders to n8n on completion, only when the total is over $999 — wired up with a Claude Code agent 👉 Step-by-step example: WooCommerce to HubSpot integration — sync orders, contacts, and deals with no custom code
Typical Use Cases
- Send Contact Form 7, Gravity Forms, or IvyForms submissions to n8n, Make, or any CRM
- Sync WooCommerce orders to HubSpot, Pipedrive, or any REST API — create a deal on payment, then PATCH it when the order status changes
- Dynamic per-event endpoints — resolve
{{ resource_id }}from the live payload into the URL at dispatch time - Replace fragile custom
wp_remote_post()integrations with a queued, retried, fully logged delivery layer - Sync WordPress users to external CRMs on registration or profile update
- Query logs, trigger retries, or manage webhooks from CI/CD pipelines or AI agents via the REST API
⚡ Webhook Actions Pro
Unlock unlimited conditions, per-webhook retry and backoff settings, type casting in payload mapping, and more.
Event Identity & Idempotency
Every dispatched webhook includes:
- Unique UUID (v4) per event
- ISO 8601 UTC timestamp
- Embedded
event.id,event.timestamp,event.versionin the payload -
HTTP headers:
X-Event-Id,X-Event-Timestamp,X-Webhook-IdX-Webhook-Id carries the webhook’s own stable UUID — distinct from the per-event
X-Event-Id. When multiple webhooks point to the same endpoint, the receiving system can useX-Webhook-Idto identify which webhook configuration triggered the delivery without inspecting the payload.
This enables downstream deduplication, idempotent workflow design, and reliable debugging across systems.
Reliable Queue & Smart Retry
Webhooks are never sent directly from request execution. Instead:
- Events are stored in a persistent database queue
- Processed asynchronously via background jobs
- Dispatched in batches to avoid performance impact
Smart retry routing:
- 5xx and 429 responses → automatic exponential backoff retry
- 4xx and 3xx responses → immediately marked as
permanently_failed - Configurable maximum retry attempts
- Full attempt history stored per event
No silent failures.
Replay Webhook Events
Webhook debugging is difficult when events cannot be reproduced.
Webhook Actions by Flow Systems allows you to replay any webhook event directly from the delivery logs — including successful deliveries and condition-skipped events.
This makes it easy to:
- Re-run automation workflows
- Debug external integrations
- Recover from temporary endpoint failures
- Test webhook consumers without recreating WordPress events
- Re-evaluate previously skipped events after changing webhook conditions
Each replay uses the original payload and event metadata, ensuring consistent behavior across retries and debugging sessions.
Conditional Dispatch
Not every WordPress event should trigger a webhook. Conditional dispatch lets you define field-level rules on any webhook — the event is only delivered if the conditions pass. Events that fail the check are logged with a skipped status and can be replayed later after adjusting the conditions.
Conditions are evaluated using dot-notation field paths. Each condition specifies a field, an optional type cast, an operator, and a comparison value. The field selector shows the live captured payload so you can click through nested structures and pick the exact path without typing it manually.
Evaluate against original or transformed payload
Each trigger schema exposes a toggle to choose which payload conditions are evaluated against:
- Original — the pre-mapping payload exactly as the WordPress hook fired (default for most use cases). Use this to filter on raw hook arguments like the new WooCommerce status in
args.2. - Transformed — the post-mapping, post-enrichment payload that will actually be sent. Use this to filter on fields injected by
fswa_payload,fswa_webhook_payload, or (Pro) Code Glue snippets — for example, dispatch only when a remote id was successfully resolved.
Operators include: equals, not equals, contains, starts with, ends with, is empty, has value, greater than, less than, array_contains, object_contains
Type casting before comparison: auto-detect, number, string, boolean, or stringify (JSON-encodes arrays and objects into a string for pattern matching)
Example — WooCommerce: fire only when a specific product is in the order
A woocommerce_order_status_changed hook passes the full order object. The payload includes args.1.line_items — an array of purchased products, each with fields like product_id, quantity, and subtotal. To send a webhook only when product ID 26 appears in the order:
- Field:
args.1.line_items - Operator:
has value→ key:product_id, value:26
The webhook stays silent for every other order and fires only when that product is purchased. No custom PHP, no extra filters — just a condition rule configured in the admin panel.
The same pattern works for any hook-based event: filter by post type, form field value, user role, order total, or any other field present in the payload.
Free plan includes one condition with AND matching. Upgrade to Pro for unlimited conditions, multiple condition groups with independent AND/OR logic per group, and ANY (OR) matching.
Synchronous Execution
By default, all webhooks are delivered asynchronously via the built-in queue — events are stored, processed in the background, and retried automatically on failure. This is the recommended approach for production sites.
For specific webhooks that require inline delivery (e.g. an internal API that must respond within the same request), you can enable Synchronous Execution per webhook:
- The webhook fires during the WordPress request that triggered it — no queue delay
- The first attempt runs blocking in the current request
- If that attempt fails with a retryable error (5xx, transport error), it automatically falls back to the queue with standard exponential backoff starting at attempt 2
- Non-retryable failures (4xx) are marked permanently failed immediately
- A warning dialog must be acknowledged before enabling, and can be dismissed permanently per-browser
Use with caution on user-facing requests — a slow or unreachable endpoint will delay page loads, form submissions, and other frontend interactions.
Delivery Observability
Operational visibility built into the admin panel:
Status states: pending, processing, success, failed (retrying), permanently_failed
- Attempt timeline per event
- HTTP status codes and response bodies
- Inspect full request payloads
- Manual retry (single or bulk)
- Replay webhook events for debugging and testing integrations
Filter by: event UUID, target URL, date range, status
Queue health metrics:
- Average attempts per event
- Oldest pending job age
- Queue stuck detection
- WP-Cron-only warning
Designed as an operations console — not just a webhook sender.
Payload Mapping
Adapt outgoing JSON payloads to match any external API:
- Rename fields using dot notation
- Restructure nested objects
- Exclude sensitive or unnecessary data
- Cast field values to number, string, or boolean before sending (e.g. WooCommerce price
"100.50"→100.5) - Store example payloads for configuration
- Modify via
fswa_payloadfilter
Payloads always include stable event metadata for consistency.
Configurable HTTP Requests
Every webhook can be configured to match exactly what the target API expects:
HTTP Method
Choose the method used for each delivery: GET, POST, PUT, PATCH, or DELETE. Default is POST.
Custom Request Headers
Add any number of key/value header pairs sent with every delivery. Header values support dot-notation paths — reference any field from the outgoing payload directly (e.g. event.id, site.url). Resolved at dispatch time against the live payload.
URL Query Parameters
Append query parameters to the endpoint URL at dispatch time. Values also support dot-notation payload resolution.
For GET and DELETE requests — where a request body is not appropriate — query parameters become the primary payload transport. If no params are configured, the full payload is sent as a ?payload= fallback. POST, PUT, and PATCH send a JSON body as normal; any configured params are appended to the URL in addition.
Request details in delivery logs
Every delivery log stores the exact headers sent and the fully resolved URL (including all query parameters), so you can inspect precisely what was dispatched.
Per-Event Dynamic URLs (Free, via filter)
Many REST APIs require an object id directly in the path — HubSpot, Pipedrive, Stripe, Notion, custom internal services. The free plugin exposes the fswa_webhook_url filter so you can rewrite the endpoint URL per event from PHP, with full access to the outgoing payload, the webhook configuration, the trigger name, and the original pre-mapping payload.
add_filter( 'fswa_webhook_url', function ( $url, $payload, $webhook, $trigger, $original ) {
if ( (int) $webhook['id'] === 30 ) {
$deal_id = $payload['_hs_deal_id'] ?? '';
return "https://api.hubapi.com/crm/objects/2026-03/deals/{$deal_id}";
}
return $url;
}, 10, 5 );
The same filter powers the (Pro) template syntax described below, so any URL you can build with {{ }} placeholders you can also build by hand on the free plan.
Dynamic URL Templates (Pro)
(Pro) Endpoint URLs can contain {{ field.path }} placeholders that are resolved per event against the live payload at dispatch time — no PHP required. Configure entirely from the webhook edit screen.
Syntax
https://api.hubapi.com/crm/objects/2026-03/deals/{{ _hs_deal_id }}
https://api.example.com/v1/resources/{{ resource_id }}/notes
https://api.example.com/users/{{ user.id }}/orders/{{ order.id }}
Same dot-notation as custom headers and URL parameters. Values are rawurlencode()‘d before substitution to keep the URL valid.
Resolution order
The template is resolved against the outgoing (post-mapping) payload first. If a placeholder is not found there, the original pre-mapping payload is consulted as a fallback — so paths from the captured event keep working even after payload mapping renames or removes top-level fields.
Example — WooCommerce → HubSpot deal update
- On
woocommerce_payment_complete, send a POST tohttps://api.hubapi.com/crm/objects/2026-03/dealsto create the deal. Store the returned deal id in the WooCommerce order’s post meta. - On
woocommerce_order_status_changed, configure a second webhook with endpoint URLhttps://api.hubapi.com/crm/objects/2026-03/deals/{{ _hs_deal_id }}and methodPATCH. Inject_hs_deal_idinto the payload (read from order meta), and the URL resolves to the right HubSpot deal on every event.
This pattern works for any REST API that uses resource ids in the URL path. Injecting the id from external storage (post meta, options, transients) can be done with the fswa_webhook_payload filter on the free plan, or (Pro) with no code at all using Webhook Actions Pro Code Glue.
REST API Access with Token Authentication
The plugin exposes a full operational REST API (/wp-json/fswa/v1/) that powers the admin interface and can also be used directly by external tools, automation systems, AI agents, and CI/CD pipelines.
Every endpoint supports dual authentication:
- WordPress admin session (cookie-based, used by the admin panel)
- API token — for programmatic access without a browser session
API Tokens
Create tokens directly from the API Tokens screen in the admin panel. Each token is assigned one of three scopes:
read— GET access to webhooks, logs, queue, health, triggers, and schemasoperational— Read + toggle webhooks on/off, retry and replay log entries, execute queue jobsfull— Operational + create, update, and delete webhooks, schemas, and queue jobs
Token authentication is accepted via:
X-FSWA-Token: <token>header (recommended)Authorization: Bearer <token>header?api_token=<token>query parameter
Tokens can be set to expire and rotated at any time. Rotation issues a new secret immediately while preserving the token’s name, scope, and settings. Token management always requires a WordPress admin login — tokens cannot be used to create or manage other tokens.
Full REST API documentation: REST API Reference
AI Agents and Programmatic Automation
The REST API makes Webhook Actions by Flow Systems accessible to AI-powered tools and coding agents.
Automation systems, CI pipelines, and AI coding assistants (such as Claude Code or Cursor) can safely interact with webhook infrastructure using API tokens without requiring WordPress admin sessions.
Typical AI-driven workflows …
