Endpoints
All endpoints are prefixed with https://caravanguide.co.uk/api/v1/. All responses are JSON. Pagination uses page and limit query parameters unless otherwise noted.
Health
No authentication required. Suitable for uptime monitors and load balancers.
GET /api/v1/health
Returns the current platform status with a database connectivity check. Returns HTTP 200 when healthy and 503 when degraded.
Response
{
"status": "ok",
"timestamp": "2026-04-13T12:00:00Z",
"version": "v1",
"checks": {
"database": "ok",
"platform": "operational"
}
}
| Field | Values | Description |
|---|---|---|
status | ok | degraded | Overall platform health |
checks.database | ok | error | Database connectivity |
checks.platform | operational | disabled | API platform kill-switch state |
A 503 response body uses the same shape as above with "status": "degraded". The HEAD method is also supported for lightweight polling.
GET /api/v1/status
Returns uptime percentages, component health, and recent incidents for the public status page. No authentication required. Cached for 60 seconds.
Human-readable dashboard: Platform status.
Response (abbreviated)
{
"overall": "operational",
"timestamp": "2026-06-04T12:00:00Z",
"monitoring_since": "2026-06-01 08:00:00",
"uptime": { "24h": { "platform": 100 }, "7d": { "platform": 99.98 } },
"components": [{ "id": "api", "name": "API", "status": "operational", "uptime": { "90d": 99.99 } }],
"incidents": []
}
Valuations
Requires scope: valuations:read
Partner catalogue workflow
Use these endpoints together to power partner search forms with cascading dropdowns, individual field pre-fill, and valuations.
Typical integration flow
- Bootstrap on page load when you already have partial listing data (from your URL, CRM, or ad feed):
GET /valuations/catalog?bootstrap=1&caravan_type=static&manufacturer=Swift&model_name=Bordeaux&model_year=2017 - Step calls on user interaction when the user changes one dropdown:
GET /valuations/catalog?step=models&caravan_type=static&manufacturer=Swift - Resolve alias names when listing text may not match the published catalogue exactly:
GET /valuations/resolve?manufacturer=…&model_name=…&model_year=2017 - Search for prices once selection is complete (use
canonicalvalues from catalogueselectionor resolve):
GET /valuations/search?manufacturer=Swift&model_name=Bordeaux&model_year=2017
Cascade order and parent parameters
| Step | Required parent params | Returns |
|---|---|---|
caravan_types | - | Available caravan types in the published edition |
manufacturers | caravan_type (optional, default static) | Manufacturer names |
models | manufacturer | Model names (includes active alias mappings) |
years | manufacturer, model_name | Model years (newest first); may include default_listing_year on step responses |
sizes | above + model_year | Size display strings (e.g. 36×12) |
bedrooms | above (+ optional size filter) | Bedroom counts; may include null for unknown/varying counts |
Pre-fill and validation
Any catalogue request may include optional pre-fill parameters: caravan_type, manufacturer, model_name, model_year, size_display (or sd, or lf+wf), and bedrooms (use __null__ when bedroom count is unknown).
Every catalogue response includes a selection object. Each field has:
provided- whether your request included this fieldvalue- the value you sent (if provided)valid- whether the value exists in the published catalogue (nullwhen not provided)canonical- the guide’s canonical spelling to use in downstream search calls (when valid)
Catalogue endpoints return filter values only - no retail or trade prices. Prices are returned by /valuations/search and /valuations/pricing.
Kill-switch keys (admin): valuations.catalog, valuations.resolve (or category valuations).
GET /api/v1/valuations/catalog
Stepwise catalogue options for partner cascading dropdowns (make → model → year → size → bedrooms). Returns filter values only - no retail or trade prices. Use with optional pre-fill parameters so each field can be populated individually from your listing data or URL query string.
Modes
- Step - pass
stepto load one dropdown level. - Bootstrap - pass
bootstrap=1to hydrate all applicable option lists in one call (ideal for page load when you already know part of the spec).
Step values
caravan_types · manufacturers · models · years · sizes · bedrooms
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
step | string | Step mode | One of the step values above |
bootstrap | 0|1 | Bootstrap mode | When 1, returns all option lists for the supplied selection (omit step) |
caravan_type | string | No | static | touring | motorhome (default: static) |
manufacturer | string | Parent / pre-fill | Required for models and below; optional pre-fill on any call |
model_name | string | Parent / pre-fill | Required for years and below |
model_year | int | Parent / pre-fill | Required for sizes and bedrooms |
size_display | string | No | Pre-fill or narrow bedrooms; aliases: sd, or lf+wf |
bedrooms | int|string | No | Pre-fill bedroom count; use __null__ when bedroom count is unknown |
Step response
{
"success": true,
"data": {
"edition_date": "2026-04-01",
"step": "models",
"values": ["Challenger", "Conqueror"],
"selection": {
"caravan_type": { "provided": true, "value": "static", "valid": true, "canonical": "static" },
"manufacturer": { "provided": true, "value": "Swift", "valid": true, "canonical": "Swift" },
"model_name": { "provided": false, "value": null, "valid": null, "canonical": null }
}
},
"meta": { "request_id": "...", "version": "v1" }
}
Bootstrap response
{
"success": true,
"data": {
"edition_date": "2026-04-01",
"mode": "bootstrap",
"options": {
"caravan_types": ["static"],
"manufacturers": ["Swift", "ABI"],
"models": ["Challenger"],
"years": [2022, 2021, 2020],
"sizes": ["36×12"],
"bedrooms": [2, 3]
},
"selection": { "...": "per-field provided / valid / canonical" }
}
}
Each selection field includes provided, value, valid, and canonical. Use canonical values when calling /valuations/search.
Example requests
GET /api/v1/valuations/catalog?step=manufacturers&caravan_type=static
GET /api/v1/valuations/catalog?step=years&manufacturer=Swift&model_name=Bordeaux
GET /api/v1/valuations/catalog?bootstrap=1&manufacturer=Swift&model_name=Bordeaux&model_year=2017&bedrooms=2
Errors
400 invalid_request- missingstep(and nobootstrap=1), unknown step, or missing parent params (e.g.manufacturer requiredforstep=models)503 internal_error- no published guide edition available
GET /api/v1/valuations/resolve
Resolve trade or alias manufacturer/model/year to the canonical catalogue identity for form pre-fill and mapping metadata. Optional size and bedroom parameters match the guide alias resolver. For prices, call /valuations/search with the original listing make/model/year (or pass mapping_id when using the canonical identity).
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
manufacturer | string | Yes | As shown on the partner listing |
model_name | string | Yes | |
model_year | int | Yes | 1900–2100 |
caravan_type | string | No | default: static |
size_display / sd / lf+wf | string | No | Optional size filter |
bedrooms | int|string | No | Optional; __null__ for unknown count |
listing_dg / listing_ch | 0|1 | No | For mappings conditioned on double glazing + central heating |
Response (matched)
{
"success": true,
"data": {
"edition_date": "2026-04-01",
"matched": true,
"resolution_type": "family",
"family_id": 1234,
"manufacturer": "Swift",
"model_name": "Challenger",
"model_year": 2020,
"mapping_id": 56,
"delta_retail": -4000,
"delta_trade": -4000,
"mapped_from": { "manufacturer": "…", "model_name": "…", "model_year": 2019 },
"mapped_to": { "manufacturer": "Swift", "model_name": "Challenger", "model_year": 2020 },
"mapping_note": ""
},
"meta": { "request_id": "...", "version": "v1" }
}
delta_retail / delta_trade are fixed pounds applied after Market Pulse (same as the public guide). Pass mapping_id into search, pricing, or history when you look up by canonical family instead of the alias text.
Other outcomes
matched: false- no mapping or direct catalogue match; HTTP200resolution_type: "note_only"- informational mapping only (no canonical family); includesmapping_notemulti_layout: true- multiple family IDs when alias resolves to several layouts; includesfamily_idsarray
GET /api/v1/valuations/search
Search valuations by manufacturer, model name, model year, and caravan type. Returns retail and trade values for the current published edition (Market Pulse, then any mapping £ adjustment). Automatically falls back to alias mappings when no direct match is found — prefer the original listing text so mapped prices apply.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
manufacturer | string | Yes | Listing or catalogue manufacturer (e.g. Swift). Prefer original listing text for aliases |
model_name | string | Yes | Model name (e.g. Bordeaux) |
model_year | int | Yes | 4-digit year (1900–2100) |
caravan_type | string | No | static | touring | motorhome (default: static) |
mapping_id | int | No | From resolve; applies mapping £ deltas when searching by canonical identity |
page | int | No | Page number (default: 1) |
limit | int | No | Results per page, 1–50 (default: 24) |
Response
{
"success": true,
"data": {
"edition_date": "2026-04-01",
"page": 1, "limit": 24, "total": 3,
"market_pulse_pct": 100,
"mapping": null,
"results": [
{ "family_id": 1234, "manufacturer": "Swift", "model_name": "Bordeaux",
"model_year": 2017, "variant_key": "SE", "caravan_type": "static",
"bedrooms": 2, "size_label": "36×12", "length_ft": 36, "width_ft": 12,
"retail": 18500, "trade": 15200, "retail_base": 18500, "trade_base": 15200 }
]
},
"meta": { "request_id": "...", "version": "v1" }
}
When a mapping applies, mapping.mapped is true and includes mapping_id, mapped_from, mapped_to, public_note, delta_retail, and delta_trade.
GET /api/v1/valuations/cascade
All variants for a given manufacturer + model across all years (flat list with sizes, bedrooms, and prices). For interactive dropdowns and individual field pre-fill, prefer /valuations/catalog.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
manufacturer | string | Yes | |
model_name | string | Yes | |
caravan_type | string | No | default: static |
GET /api/v1/valuations/pricing
Current and previous edition pricing for a specific family. Includes market_pulse_pct adjustment, then optional fixed guide-mapping £ deltas when mapping_id is supplied.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
family_id | int | Yes | From search, resolve, or cascade results |
mapping_id | int | No | From resolve or search.mapping; applies mapping £ to current and previous |
Response fields
retail- market-pulse-adjusted retail price (+ mapping £ when applicable)retail_base- guide retail price before market pulse / mappingtrade- market-pulse-adjusted trade price (+ mapping £ when applicable)mapping- present whenmapping_idapplied (delta_retail/delta_trade)previous- same fields for the prior edition (null if first appearance)
Certificates
Read endpoints require: certificates:read · Write requires: certificates:write (enterprise only)
GET /api/v1/certificates/verify
Verify a certificate by its number.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
certificate_number | string | Yes |
Response
{
"data": {
"certificate_number": "CG-2026-abc123",
"valid": true, "status": "active",
"issued_at": "2026-01-15 10:00:00", "expires_at": "2027-01-15 10:00:00",
"manufacturer": "Swift", "model_name": "Challenger", "model_year": 2020,
"caravan_type": "touring"
}
}
POST /api/v1/certificates/issue
Issue a new certificate. Enterprise / write access only.
This is a write endpoint. An Idempotency-Key header is required.
Request Body (JSON)
{
"family_id": 1234,
"valid_months": 12,
"notes": "Issued via API for dealer ref #45678"
}
Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | application/json |
Idempotency-Key | Yes | Client-chosen unique key for this operation (max 190 chars). Same key + same body = replay. Same key + different body = 409. |
Response
201 Created on first successful issue. 200 with X-Idempotency-Replayed: true on replay.
Trust Badge
Requires scope: trust_badge:read
GET /api/v1/trust-badge/status
Returns active trust badge status for a domain.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | e.g. acme-caravans.co.uk (no scheme, no trailing slash) |
GET /api/v1/trust-badge/verify
Returns a simple verified: true/false with the verification timestamp. Use this for lightweight programmatic checks.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | Yes |
Valuation History
Requires scope: valuations:read
GET /api/v1/valuations/history
Returns retail and trade price history across published editions for a specific caravan family. Ideal for rendering price-movement charts and trend graphs.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
family_id | int | Yes | ID from /valuations/search results |
limit | int | No | Number of editions to return, 1–24 (default: 12) |
Response
{
"success": true,
"data": {
"family_id": 1234,
"manufacturer": "Swift",
"model_name": "Challenger",
"model_year": 2020,
"caravan_type": "touring",
"variant_key": "SE",
"total": 12,
"history": [
{ "edition_date": "2025-04-01", "retail": 14995, "trade": 11500 },
{ "edition_date": "2025-10-01", "retail": 15250, "trade": 11750 },
{ "edition_date": "2026-04-01", "retail": 15495, "trade": 12000 }
]
},
"meta": { "request_id": "...", "version": "v1" }
}
History is returned oldest-first, suitable for direct use in chart libraries.
Certificate History
Requires scope: certificates:read
GET /api/v1/certificates/history
Returns certificates issued for a specific caravan family, identified by family_id. Shows how many times a caravan has been independently valued and certificated.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
family_id | int | Yes | ID from /valuations/search results |
limit | int | No | Max results, 1–50 (default: 20) |
Response
{
"success": true,
"data": {
"family_id": 1234,
"manufacturer": "Swift",
"model_name": "Challenger",
"model_year": 2020,
"caravan_type": "touring",
"total": 2,
"certificates": [
{
"certificate_number": "CGV-20260101-A1B2C3D4E5F6",
"issued_at": "2026-01-01 10:30:00",
"issued_for": "John Smith",
"edition_date": "2026-04-01"
}
]
},
"meta": { "request_id": "...", "version": "v1" }
}
Announcements
No specific scope required - available to all authenticated API clients.
GET /api/v1/announcements
Returns active announcements from Caravan Guide - platform news, valuation edition releases, or partner notices. Suitable for displaying in-app banners or notification feeds.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | int | No | Max results, 1–50 (default: 10) |
Response
{
"success": true,
"data": {
"total": 1,
"announcements": [
{
"id": 12,
"title": "Spring 2026 edition now live",
"body": "The April 2026 valuation edition has been published...",
"published_at": "2026-04-01 09:00:00",
"current_until": "2026-04-30 23:59:59"
}
]
},
"meta": { "request_id": "...", "version": "v1" }
}
Account
No specific scope required beyond a valid authenticated credential.
GET /api/v1/account/me
Returns details about the authenticated API client: identity, access tier, granted scopes, and current-month usage. Use this to display subscription status in your app or to verify your integration is using the correct credentials.
The docs_access_enabled field is retained for compatibility and is always true - API documentation is public and no longer gated by commercial access.
Response
{
"success": true,
"data": {
"client": {
"id": "d05aed00-2ef9-4ff5-ab50-38e61bda55ac",
"name": "UK Caravan Portal",
"environment": "live",
"status": "active",
"created_at": "2026-04-01 12:00:00"
},
"access": {
"commercial_status": "live_enabled",
"commercial_tier": "partner_pro",
"live_enabled": true,
"sandbox_enabled": true,
"write_scopes_enabled": false,
"docs_access_enabled": true,
"monthly_request_allowance": 50000,
"access_ends_at": null
},
"scopes": ["valuations:read", "certificates:read", "trust_badge:read", "announcements:read"],
"usage": {
"month": "2026-04",
"requests_this_month": 1842,
"allowance": 50000
}
},
"meta": { "request_id": "...", "version": "v1" }
}