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\Webhooks listens on the as24ci_lead_saved action, but in the current plugin version that action is not dispatched anywhere in the code (the lead is saved via Leads_CPT::save_lead() without firing the hook), so the new_lead webhook 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 the as24ci_vehicle_imported action). 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_lead event: note the caveat above — the as24ci_lead_saved action is not currently dispatched, so this event will not fire in the current plugin version even with a URL configured.
  • For the new_import event: the import engine must be configured and running. See Import Engine.

Step by step instructions

  1. 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.
  2. Enter a valid https:// URL for each event you want to receive.
  3. 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.
  4. Save the settings. The plugin stores the values in the as24ci_webhook_url_new_lead, as24ci_webhook_url_new_import and as24ci_webhook_secret options.
  5. Trigger a test event: - For new_lead: submit a test contact form on the front-end. - For new_import: run an import that creates or updates at least one vehicle.
  6. 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:

  1. Read the raw request body without re-encoding it.
  2. Compute hash_hmac('sha256', body, secret) using the same shared secret.
  3. Compare with X-AS24CI-Signature using a constant-time comparison (e.g. hash_equals in 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 4xx responses 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 keyStored value
as24ci_webhook_url_new_leadURL invoked for the new_lead event. Empty disables the event.
as24ci_webhook_url_new_importURL invoked for the new_import event. Empty disables the event.
as24ci_webhook_secretShared 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 valid https:// 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_lead payload only includes the small set of fields shown above. Additional lead metadata is available via the WP REST API or by querying the as24ci_lead post type with normal WordPress functions.
  • The new_import payload 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_retry event 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_import deliveries — 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.