Documentation · Technical Documentation
Webhooks
This document describes the outbound HTTP webhooks fired by the ADP Car Market Hub plugin so that external CRM, notification or automation systems can react to plugin events in real time.
When to use this document
Read this document if you need to:
- Connect the plugin to an external CRM or notification service (for example a workflow automation tool) so that new leads or newly imported vehicles trigger actions in another system.
- Implement a receiver endpoint that verifies webhook authenticity using the HMAC signature.
- Diagnose missed or duplicated webhook deliveries.
For inbound HTTP, see REST API Endpoints.
Overview
The plugin can fire two outbound webhook events:
new_lead— intended to fire when a contact-form submission is saved as a lead post.AS24CI\Webhookslistens on theas24ci_lead_savedaction, but in the current plugin version that action is not dispatched anywhere in the code (the lead is saved viaLeads_CPT::save_lead()without firing the hook), so thenew_leadwebhook does not currently fire. Treat this event as dormant until the firing point is reinstated.new_import— fired when a vehicle is created or updated during an import (via theas24ci_vehicle_importedaction). This event is active.
Each event POSTs a JSON payload to a URL configured by the administrator. When a shared secret is configured, each request also carries an HMAC-SHA256 signature header that the receiver can use to verify the payload.
Webhooks are independent: configuring one does not enable the other. Leaving a URL empty disables that event entirely.
Requirements or prerequisites
- A reachable HTTPS endpoint on the receiving side.
- (Optional but strongly recommended) a shared secret stored in the plugin settings and on the receiver, used to verify the signature.
- For the
new_leadevent: note the caveat above — theas24ci_lead_savedaction is not currently dispatched, so this event will not fire in the current plugin version even with a URL configured. - For the
new_importevent: the import engine must be configured and running. See Import Engine.
Step by step instructions
- Open the plugin admin and locate the webhook fields. They are exposed on the Leads tab as the inputs labelled New lead webhook URL, New import webhook URL and Webhook secret.
- Enter a valid
https://URL for each event you want to receive. - Generate a strong random secret (for example a 32+ character string) and paste it into the Webhook secret field. Configure the same value on the receiver.
- Save the settings. The plugin stores the values in the
as24ci_webhook_url_new_lead,as24ci_webhook_url_new_importandas24ci_webhook_secretoptions. - Trigger a test event:
- For
new_lead: submit a test contact form on the front-end. - Fornew_import: run an import that creates or updates at least one vehicle. - Confirm receipt and signature verification on the receiver side.
Payload reference
All payloads are JSON objects with event, timestamp (ISO 8601,
UTC) and an event-specific data block.
new_lead
{
"event": "new_lead",
"timestamp": "2025-01-01T12:00:00+00:00",
"lead_id": 123,
"data": {
"name": "",
"email": "",
"phone": "",
"message": "",
"vehicle_id": 0,
"vehicle_title": "",
"vehicle_url": ""
}
}
new_import
{
"event": "new_import",
"timestamp": "2025-01-01T12:00:00+00:00",
"post_id": 456,
"listing_id": "",
"data": {
"title": "",
"url": "",
"make": "",
"model": "",
"price": 0
}
}
The new_import payload is fired for both new inserts and updates.
The hook callback receives an is_update flag internally; the
outbound payload itself does not include this flag in the current
plugin version. Verify whether your integration requires
distinguishing the two cases and confirm the current behaviour
against the source before publishing customer-facing wording.
Authentication and signature verification
When the as24ci_webhook_secret option is set, the plugin adds the
header:
X-AS24CI-Signature: <hmac_sha256(payload_json, secret)>
The signature is computed over the exact JSON body sent in the request. To verify on the receiver:
- Read the raw request body without re-encoding it.
- Compute
hash_hmac('sha256', body, secret)using the same shared secret. - Compare with
X-AS24CI-Signatureusing a constant-time comparison (e.g.hash_equalsin PHP).
If no secret is configured, the X-AS24CI-Signature header is not
sent. Production deployments should always configure a secret.
Delivery, retries and timeouts
- Requests use
wp_remote_post()with a 15-second timeout. - The first attempt is non-blocking (
fire and forget). The plugin then schedules a follow-up cron event (as24ci_webhook_retry) about 60 seconds later that performs a blocking re-send so the response code can be inspected. - If the response is a connection error or HTTP
5xx, the plugin schedules additional retries with exponential-style backoff (~2 minutes, then ~4 minutes), up to a maximum of three attempts in total. - HTTP
4xxresponses are treated as terminal and are not retried; fix the receiver and re-trigger the source event if needed. - Receivers should respond within 15 seconds and ideally complete any heavy work asynchronously.
Configuration reference
| Option key | Stored value |
|---|---|
as24ci_webhook_url_new_lead | URL invoked for the new_lead event. Empty disables the event. |
as24ci_webhook_url_new_import | URL invoked for the new_import event. Empty disables the event. |
as24ci_webhook_secret | Shared secret used to sign payloads. Empty disables signing. |
For the full list of plugin options, see Options And Settings Storage.
Operational notes
- URLs are validated with
filter_var( ..., FILTER_VALIDATE_URL ). Invalid URLs are silently skipped — set validhttps://URLs in production. - The plugin only fires webhooks; it does not maintain a delivery queue, replay log or dead-letter store. If reliable, ordered delivery is critical for your use case, run the receiver through a queueing layer (for example a serverless function with a built-in retry queue).
- Each webhook is fired from the same WordPress request that generated the source event. Slow receivers will not stall the user-facing request because the first attempt is non-blocking.
- The
new_leadpayload only includes the small set of fields shown above. Additional lead metadata is available via the WP REST API or by querying theas24ci_leadpost type with normal WordPress functions. - The
new_importpayload intentionally stays small. To retrieve the full vehicle record, fetch/wp-json/as24ci/v1/vehicles/<post_id>(when the public REST API is enabled).
Troubleshooting
- Webhook never arrives — verify the URL is HTTPS, reachable from the WordPress server, and validates as a URL. Check the plugin logs and your webserver error log.
- Webhook arrives once but no retries — the first attempt is
intentionally fire-and-forget; verify the
as24ci_webhook_retryevent is being scheduled (it relies on WP-Cron or your external cron). - Signature mismatch on the receiver — confirm both sides use the exact same secret, and that the receiver verifies the raw request body without re-serialising or pretty-printing it before hashing.
- Duplicate
new_importdeliveries — change detection skips vehicles whose payload is unchanged, but a forced full sync may re-emit events for already-known listings. See Import Engine for the change-detection rules. - Stuck retries — WP-Cron requires regular site traffic to fire. On low-traffic sites, configure a real cron job or the REST cron endpoint described in Cron Events And Scheduler.