Outgoing Webhooks
Pro feature. Available in Listora Pro.
Availability: Pro only. Requires Listora Pro. Send real-time HMAC-signed HTTP POSTs to external systems (Zapier, n8n, Make, Slack, your CRM, custom services) whenever something happens in your directory - a new listing is published, a review is posted, a claim is approved, a coupon is redeemed. Webhooks are queued via Action Scheduler, retried on failure, signed for authenticity, and individually toggleable per endpoint per event.

What it is
If you've ever wanted "when a new business listing is approved, post a message in Slack" or "when a review hits 5 stars, push the listing into our HubSpot pipeline" - that's what Outgoing Webhooks is for. It turns Listora into a first-class event source for the rest of your stack.
Under the hood:
- Endpoints are stored as a custom post type (
wb_listora_webhook) so each subscription has its own admin row, status, last-delivery log, and individually selectable event subscriptions. - Every event is HMAC-SHA256 signed with a per-endpoint secret in the
X-Listora-Signatureheader, plus a timestamp + nonce for replay protection - your receiver verifies authenticity before processing. - Deliveries run on Action Scheduler (
wb_listora_pro_deliver_webhookjob, groupwb-listora-pro), so a slow receiver never blocks your site. Failed deliveries retry with exponential backoff. - Delivery logs persist with response code, body excerpt, duration, attempt count - pruned automatically via
wb_listora_pro_webhook_log_cleanupcron. - REST routes are registered (in
wb_listora_rest_api_init) so you can also create + manage webhooks programmatically.
Events available out of the box:
| Event | Fires when |
|---|---|
listing_created |
A listing is created via REST submission |
listing_updated |
A listing's fields are edited |
listing_status_changed |
Status transitions (pending → publish, publish → expired, etc.) |
listing_expired |
Listing's expiration date passes (cron-driven) |
review_submitted |
A new review is posted |
review_updated |
A review is edited (or moderation status changes) |
claim_submitted |
A business-claim request is submitted |
claim_updated |
A claim is approved / rejected / reassigned |
coupon_redeemed |
A discount code is used at submission |
need_posted |
(Needs Marketplace) A need is posted publicly |
How you use it
As a site owner - set up a webhook
- Enable the feature: Listora → Settings → Features → Outgoing Webhooks (on by default).
- Open the webhook admin: Listora menu → Webhooks.
- Add a new endpoint:
- Name - e.g. "Slack: #new-listings"
- URL - the receiver URL (
https://hooks.slack.com/services/…, your Zap, etc.) - Secret - a long random string; share it with the receiver
- Events - tick the events this endpoint should subscribe to
- Status - Active
- Save. The endpoint is live.
- Test: edit a listing on your site → save → check the Delivery Log row for that endpoint. You should see a 2xx response code.
As a developer - verify HMAC signatures
The receiver should:
- Read the
X-Listora-Signatureheader. - Recompute
hash_hmac('sha256', $raw_body, $secret)and compare with the header value using a constant-time comparison. - Reject the request if the signatures don't match.
- Reject if the
X-Listora-Timestampis more than ~5 minutes off (replay protection). - Process the JSON body - top-level keys:
event,id,timestamp,data(the event payload).
Example PHP verification:
$body = file_get_contents( 'php://input' );
$signature = $_SERVER['HTTP_X_LISTORA_SIGNATURE'] ?? '';
$expected = hash_hmac( 'sha256', $body, $your_secret );
if ( ! hash_equals( $expected, $signature ) ) {
http_response_code( 401 );
exit;
}
$payload = json_decode( $body, true );
// ... process $payload ...
Settings & options
| Setting | Location | Default | Notes |
|---|---|---|---|
| Feature toggle | Settings → Features → Outgoing Webhooks | On | |
| Endpoint CRUD | Listora → Webhooks | - | One row per receiver |
| Per-endpoint events | (per row) | None until ticked | Subscribe each endpoint to specific events only |
| HMAC secret | (per row) | Required | Used for X-Listora-Signature |
| Retry policy | (system) | Exponential backoff via Action Scheduler | Retries on non-2xx responses |
| Log retention | wb_listora_pro_webhook_log_cleanup cron |
30 days | Old delivery rows are pruned |
Developer filters:
wb_listora_pro_webhook_payload- modify the payload before signing/sending.wb_listora_pro_webhook_headers- add custom headers to outgoing requests.wb_listora_pro_webhook_request_args- modify thewp_remote_post()args (e.g. timeout, sslverify).
Related
- Payment Webhook Receiver (Pro) (docs in progress) - the inbound side: how Listora accepts payment webhooks from Stripe/PayPal/Paddle.
- BuddyPress Integration (Pro) - another way to react to listing events, but routed into BP activity streams + notifications.
- Developer Reference: REST API - webhooks are also manageable via REST.
- Developer Reference: Hooks - the underlying
wb_listora_*events these webhooks listen to.