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:

  1. Public vehicle data — read-only listing and detail endpoints. Disabled by default; must be turned on by an administrator.
  2. Favorites helper — used by the front-end favorites page to fetch vehicle data for IDs the visitor has stored locally.
  3. Analytics tracking pixel — accepts lightweight event notifications from the front-end script.
  4. Cron import trigger — token-protected endpoint that runs the shared import routine on demand.
  5. 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_enabled must be set to 1. Until then the routes are not registered and any request returns a 404 from 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_enabled equals 1.
  • Query parameters:
  • page — integer ≥ 1. Default 1.
  • per_page — integer between 1 and 100. Default 10.
  • make, model — exact match against the corresponding meta keys.
  • fuel_typeLIKE match 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 of date, price, mileage, title. Default date.
  • orderasc or desc (case-insensitive). Default desc.
  • 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 image field is the medium-large WordPress size of the featured image (empty string when no thumbnail exists). The currency field falls back to the value of the as24ci_default_currency option 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 to absint.
  • 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 the large size, 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 the as24ci_car CPT, 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. Default 0.
  • 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. For filter_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 HTTP 400 when 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_token option. Generate or rotate it from Import & Limits in the plugin admin.
  • Responses:
  • 403 when no token is configured or the supplied token does not match.
  • 200 with { "success": true, "message": "...", "counts": { ... } } on a successful run.
  • 429 with success: false when another import is already in progress and the runner declined to start a second one.
  • 500 when the runner threw an exception.
  • Side effect: a successful authentication updates the as24ci_last_external_cron_run option, 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 matching product_key (against License_Client::PRODUCT_KEY); a matching installation_uid when 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 429 so a burst can never hammer the API Platform.
  • Responses: 200 on a triggered refresh; 4xx/503 for the validation failures above (403 product/installation mismatch, 409 not licensed / replayed nonce, 401 bad timestamp/signature, 503 when no signal secret is provisioned).

Operational notes

  • The public vehicle endpoints execute standard WP_Query calls 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 a meta_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 the Authorization: Bearer header to avoid leaking the token via referrer headers, browser history or webserver access logs.

Configuration reference

Option keyPurpose
as24ci_rest_api_enabledWhen '1', registers /vehicles and /vehicles/<id>. Default '0'.
as24ci_default_currencyCurrency code returned by the public endpoints when no per-vehicle currency is stored.
as24ci_cron_tokenBearer token expected by /cron-import. Empty disables the endpoint.
as24ci_last_external_cron_runTimestamp of the last successful external cron call. Updated automatically.

For the full list of plugin options, see Options And Settings Storage.

Troubleshooting

  • /vehicles returns 404 — the public API is disabled. Set as24ci_rest_api_enabled to '1' in Import & Limits (or via WP-CLI / update_option).
  • /cron-import returns 403 — either no token is configured yet, or the supplied value does not match. Generate a new token from the admin and retry.
  • /cron-import returns 429 — 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 vehicles array 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 400 on /analytics/track — the event requires a published vehicle post but post_id references a draft, deleted or non-vehicle post.