Documentation · Technical Documentation
REST API Endpoints
This document describes the REST API routes registered by the
ADP Car Market Hub plugin under the as24ci/v1 namespace, including
their methods, parameters, authentication model and intended use.
When to use this document
Read this document if you need to:
- Build a custom integration that consumes vehicle data from the plugin over HTTP.
- Trigger imports from an external scheduler instead of WP-Cron.
- Understand which endpoints are public, which are gated by an admin-controlled toggle, and which require a token.
- Diagnose unexpected 403 / 404 responses from the plugin's REST routes.
For the AJAX (admin-ajax.php) interface, see AJAX Actions. For outbound HTTP calls to external systems, see Webhooks.
Overview
All routes registered by the plugin use the WordPress REST API and
share the namespace as24ci/v1. Endpoints fall into four groups:
- Public vehicle data — read-only listing and detail endpoints. Disabled by default; must be turned on by an administrator.
- Favorites helper — used by the front-end favorites page to fetch vehicle data for IDs the visitor has stored locally.
- Analytics tracking pixel — accepts lightweight event notifications from the front-end script.
- Cron import trigger — token-protected endpoint that runs the shared import routine on demand.
- License refresh signal — signal-only endpoint the ADP Car Market Hub API Platform calls so the plugin re-pulls its authoritative license / feature-rights state.
The full base URL of any endpoint is the WordPress REST root followed
by the route. On a typical site this is
https://example.com/wp-json/as24ci/v1/....
Requirements or prerequisites
- WordPress with the REST API enabled (the WordPress default).
- Pretty permalinks for path-style REST URLs. With plain permalinks
the endpoints are still reachable via
?rest_route=. - For the public vehicle endpoints: the option
as24ci_rest_api_enabledmust be set to1. Until then the routes are not registered and any request returns a404from WordPress. - For the cron import endpoint: a cron token must be generated in the Import & Limits admin tab.
Endpoint reference
GET /as24ci/v1/vehicles
Returns a paginated, filterable list of imported vehicles whose CPT
post status is publish.
- Auth: none (public). Route is only registered when
as24ci_rest_api_enabledequals1. - Query parameters:
page— integer ≥ 1. Default1.per_page— integer between 1 and 100. Default10.make,model— exact match against the corresponding meta keys.fuel_type—LIKEmatch against the mapped fuel type meta key.year_min,year_max— numeric range against_as24ci_year.price_min,price_max— numeric range against_as24ci_price.orderby— one ofdate,price,mileage,title. Defaultdate.order—ascordesc(case-insensitive). Defaultdesc.- Response shape:
``
json { "vehicles": [ { "id": 123, "title": "...", "url": "...", "image": "...", "make": "...", "model": "...", "year": 0, "price": 0, "currency": "EUR", "mileage": 0, "condition": "...", "fuel_type": "...", "transmission": "...", "body_type": "...", "color": "...", "doors": 0, "horse_power": 0, "vin": "...", "listing_id": "..." } ], "total": 0, "pages": 0, "page": 1, "per_page": 10 }`` - Notes: The
imagefield is the medium-large WordPress size of the featured image (empty string when no thumbnail exists). Thecurrencyfield falls back to the value of theas24ci_default_currencyoption when no per-vehicle currency is stored.
GET /as24ci/v1/vehicles/<id>
Returns full details for a single vehicle.
- Auth: none (public). Same gating as the list endpoint.
- Path parameter:
id— positive integer. Validated and cast toabsint. - Response: All fields from the list response plus:
description— uses the WordPress excerpt when present, otherwise the trimmed post content (≈55 words).images— array of attachment URLs at thelargesize, combining manual gallery images (_as24ci_manual_image_ids) and imported images (_as24ci_image_ids); falls back to the featured image when both are empty.equipment_standard,equipment_optional— arrays of strings.seller— display name of the dealer.- Errors:
404(as24ci_vehicle_not_found) when the post does not exist, is not theas24ci_carCPT, or is not published.
POST /as24ci/v1/favorites
Used by the front-end favorites page to fetch vehicle summary data for the IDs the visitor has stored in local browser storage.
- Auth: none (public). Always registered.
- Body: JSON object with
ids, an array of post IDs. Validated to be an array; sanitised to a unique list of positive integers. Up to 50 IDs are processed per call. - Response:
{ "vehicles": [ ... ] }. - Notes: The endpoint reads only published vehicles. Posts the visitor no longer has access to (deleted, draft, wrong post type) are silently omitted.
POST /as24ci/v1/analytics/track
Receives view, archive view, compare view, favorites view, filter search, contact-open and lead-sent events from the analytics tracking pixel.
- Auth: none (public). Always registered.
- Body parameters:
post_id— integer ≥ 0. Default0.event_type— must be one of the allowed event names:view,view_archive,view_compare,view_favorites,filter_search,contact_open,lead_sent.extra_data— optional sanitised string. Forfilter_search, the string must be a JSON object containing the active filter key/value pairs; the server applies the same minimisation logic used by direct PHP tracking before storing.- Response:
{ "tracked": true }on success,{ "tracked": false }with HTTP400when the event requires a vehicle post that does not exist or is unpublished. - Notes: This endpoint is intentionally permissive so anonymous visitors can send analytics events. Do not rely on it for authoritative business data; see Analytics Tracking for retention and privacy notes.
GET /as24ci/v1/cron-import
Token-protected endpoint that runs the shared import routine. It
delegates to the same Scheduler::run_import() method used by the
WP-Cron hook and the Trigger now admin button.
- Auth: bearer token. Provide the token via either the HTTP
header
Authorization: Bearer <token>(preferred — keeps the token out of access logs) or the?token=<token>query parameter. - Token storage: persisted in the
as24ci_cron_tokenoption. Generate or rotate it from Import & Limits in the plugin admin. - Responses:
403when no token is configured or the supplied token does not match.200with{ "success": true, "message": "...", "counts": { ... } }on a successful run.429withsuccess: falsewhen another import is already in progress and the runner declined to start a second one.500when the runner threw an exception.- Side effect: a successful authentication updates the
as24ci_last_external_cron_runoption, which the System & Help tab uses to confirm that the external cron is reaching the site.
POST /as24ci/v1/license-refresh-signal
Signal-only endpoint that the ADP Car Market Hub API Platform calls
after a license or feature-right change so the plugin re-pulls its
authoritative state at once. Owned by
AS24CI\License_Refresh_Signal and registered unconditionally
(like /cron-import), independent of as24ci_rest_api_enabled.
- Auth: handled inside the callback using a signal-only trust
model. Nothing from the request body is trusted as data; the
request only triggers
License_Manager::refresh(). The handler enforces, in order:POST+ JSON content type; a matchingproduct_key(againstLicense_Client::PRODUCT_KEY); a matchinginstallation_uidwhen both sides have one; a configured local license; a provisioned per-installation refresh-signal secret; a fresh timestamp header and unused nonce (replay protection, 5-minute window); and an HMAC-SHA256 signature over the timestamp + raw body. - Rate limiting: repeated signals within a 30-second window are
accepted-but-not-refreshed and answered with
429so a burst can never hammer the API Platform. - Responses:
200on a triggered refresh;4xx/503for the validation failures above (403product/installation mismatch,409not licensed / replayed nonce,401bad timestamp/signature,503when no signal secret is provisioned).
Operational notes
- The public vehicle endpoints execute standard
WP_Querycalls and honour normal WordPress object caching. Repeated identical requests benefit from the post and post-meta caches. - Numeric filters (
year_min/year_max,price_min/price_max) are added to ameta_query. On large catalogues, ensure the underlying meta keys are indexed at the database level if you expect heavy traffic. Verify the exact indexing strategy in the current plugin version before publishing. - The list endpoint applies
update_postmeta_cache()for the returned posts to keep response times predictable. - The favorites endpoint hard-caps each request at 50 IDs to prevent abuse and to keep response payloads reasonable.
- The cron import endpoint sets
nocache_headers()so caching proxies do not interfere with scheduled runs. - The token comparison uses
hash_equals()to mitigate timing attacks. Even so, prefer theAuthorization: Bearerheader to avoid leaking the token via referrer headers, browser history or webserver access logs.
Configuration reference
| Option key | Purpose |
|---|---|
as24ci_rest_api_enabled | When '1', registers /vehicles and /vehicles/<id>. Default '0'. |
as24ci_default_currency | Currency code returned by the public endpoints when no per-vehicle currency is stored. |
as24ci_cron_token | Bearer token expected by /cron-import. Empty disables the endpoint. |
as24ci_last_external_cron_run | Timestamp of the last successful external cron call. Updated automatically. |
For the full list of plugin options, see Options And Settings Storage.
Troubleshooting
/vehiclesreturns404— the public API is disabled. Setas24ci_rest_api_enabledto'1'in Import & Limits (or via WP-CLI /update_option)./cron-importreturns403— either no token is configured yet, or the supplied value does not match. Generate a new token from the admin and retry./cron-importreturns429— another import is already running and a lock prevents a second concurrent run. Wait for the current run to finish; see Cron Events And Scheduler for the lock TTL.- Empty
vehiclesarray on the list endpoint with no filters — no vehicles are published, or the catalogue has not yet been imported. Check Import & Limits and the import logs. - Unexpected HTTP
400on/analytics/track— the event requires a published vehicle post butpost_idreferences a draft, deleted or non-vehicle post.