Documentation · Appendices

Webhook Event Reference

This appendix describes the outbound webhook events fired by the ADP Car Market Hub plugin.

When to use this document

Use this reference when building a receiver, when verifying signatures, or when documenting an integration. For the conceptual description, see Webhooks.

Overview

The plugin can fire two outbound webhook events:

  • new_lead — when a contact-form submission is saved as a lead.
  • new_import — when a vehicle is created or updated during an import.

Each event is a JSON POST to a URL configured by the administrator. When a shared secret is configured, the request also carries an HMAC-SHA256 signature header that the receiver can use to verify the payload.

The events are independent: configuring one URL does not enable the other. Leaving a URL empty disables that event entirely.

Current behavior note: In the current plugin version only new_import is actually dispatched. The new_lead delivery path is present (receiver, signing and the as24ci_webhook_url_new_lead option all exist) but its trigger is not fired in the current code, so configuring a new_lead URL will not produce requests yet. For lead notifications today, rely on the lead emails (see Leads Reference). The schema below documents the intended new_lead payload for receivers that want to be ready for it.

Event summary

EventTriggerConfigured by
new_leadA contact-form submission is saved (as24ci_lead_saved action).as24ci_webhook_url_new_lead option.
new_importA vehicle is created or updated during an import.as24ci_webhook_url_new_import option.

A shared signing secret is configured globally via as24ci_webhook_secret.

Payload format

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": 0,
  "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": 0,
  "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 against the current source before publishing.

Signature verification

When as24ci_webhook_secret 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 the result with X-AS24CI-Signature using a constant-time comparison (for example 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.
  • On connection errors 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 not retried; fix the receiver and re-trigger the source event if needed.
  • Receivers should respond within 15 seconds and ideally complete heavy work asynchronously.

Configuration

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. Sensitive. Empty disables signing.

URLs are validated with filter_var( ..., FILTER_VALIDATE_URL ). Invalid URLs are silently skipped — set valid https:// URLs in production.

Operational notes

  • 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 behind a queueing layer.
  • 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 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 that the URL is HTTPS, reachable from the WordPress server and validates as a URL. Check the plugin logs and the webserver error log.
  • Webhook arrives once but no retries. The first attempt is intentionally fire-and-forget; verify that 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.
  • 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 Hook Reference.