← API v2 Overview

Errors

Errors return a consistent envelope with a stable, machine-readable code and an appropriate HTTP status. Branch on the status family and the code; fall back to the message for codes you don't recognise.

Error Shape

Every error uses the same envelope. error.code is a stable machine-readable string (it will not change within a major version), error.message is human-readable and may change, and error.details is optional and code-specific; for validation_failed it carries the offending field.

{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "The email field is required.",
    "details": { "field": "email" }
  }
}

HTTP Status Families

StatusMeaningRetry?
400Malformed request (invalid JSON).No, fix the request.
401Authentication failed (missing/expired/revoked key).No, re-authenticate.
403Authenticated but not authorized (missing scope / business).No, grant the scope.
404Route or addressed resource not found.No.
409Conflict with current state (duplicate, limit, wrong state).Only after resolving the conflict.
422Validation failed, or an operation was rejected.No, fix the input.
429Rate limit exceeded.Yes, after Retry-After.
5xxServer or upstream-provider failure.Yes, with exponential backoff.

Error Codes

Treat unknown codes defensively: branch on the HTTP status family and fall back to error.message for any code your client does not yet recognise.

Authentication

Returned as 401. The bearer token is missing, malformed, expired or revoked. Re-issue or refresh the key.

CodeHTTPMeaning
authentication_required401No bearer token was supplied on the request.
authentication_invalid401The bearer token is malformed or does not match an active key.
authentication_expired401The API key has passed its expiry date.
authentication_revoked401The API key has been revoked.
authentication_blocked401The request was blocked (for example by an IP or abuse block) before authentication.

Authorization

Returned as 403. The key authenticated but is not permitted to perform the request.

CodeHTTPMeaning
scope_required403The endpoint requires a scope and the key presented none for it.
scope_denied403The key does not hold the scope this endpoint requires.
business_required403The key is not associated with a business.
business_not_found403The business the key belongs to no longer exists.
business_unverified403The business has not completed the verification required for API access.
account_frozen403The business account is frozen; API access is locked. Contact support.
account_suspended403The business account is suspended; resolve billing to restore access.
account_demo403Demo accounts cannot access the API.
account_read_only403The business account is read-only; the API is not available.
plan_upgrade_required403API access requires the Growth plan or above.
api_access_required403API 2.0 access has not been granted for this business. Request access from the dashboard.

Request Validation

The request reached a handler but the body or fields were unacceptable. For validation_failed, details.field names the offending field.

CodeHTTPMeaning
json_invalid400The request body is not valid JSON.
validation_failed422One or more fields failed validation. details.field identifies the field.
idempotency_key_invalid400The Idempotency-Key header is malformed (1-255 characters: letters, numbers, hyphens and underscores).
idempotency_key_reused422The Idempotency-Key was already used with a different request body.

Not Found

Returned as 404 (the route or addressed resource does not exist for this business), or 405 when the path exists but not for the request method - see the Allow header.

CodeHTTPMeaning
route_not_found404No endpoint matches the request method and path.
method_not_allowed405The path exists but does not support this HTTP method; the Allow response header lists the methods that are accepted.
listing_not_found404The listing could not be found (not published, or outside the for-sale/recently-sold window).
contact_not_found404The contact could not be found.
contact_note_not_found404The contact note could not be found.
lead_not_found404The lead could not be found.
lead_note_not_found404The lead note could not be found.
lead_message_not_found404The lead message could not be found.
lead_vehicle_not_found404The lead-vehicle association could not be found.
lead_appointment_not_found404The lead appointment could not be found.
appointment_not_found404The appointment could not be found.
call_not_found404The call record could not be found.
blog_not_found404The blog article could not be found.
review_not_found404The review could not be found.
document_not_found404The document could not be found.
document_signature_not_found404The document signature could not be found.
vehicle_not_found404The vehicle could not be found.
vehicle_document_not_found404The vehicle document could not be found.
vehicle_media_not_found404The vehicle media item could not be found.
vehicle_job_not_found404The vehicle job could not be found.
vehicle_job_stage_not_found404The vehicle job stage could not be found.
vehicle_job_document_not_found404The vehicle job document could not be found.
vehicle_job_purchase_not_found404The vehicle job purchase could not be found.

Conflict

Returned as 409. The request is valid but conflicts with the current state; resolve the conflict and retry.

CodeHTTPMeaning
contact_email_duplicate409A contact with this email address already exists (see POST /contacts/duplicate-check).
lead_vehicle_duplicate409The vehicle or appointment is already associated with the lead.
vehicle_drive_not_active409There is no active test drive on the vehicle to act on.
contact_login_disabled409The contact does not have customer login enabled.
vehicle_publish_limit_reached409Publishing would exceed the business's for-sale vehicle limit.
vehicle_publish_incomplete409The vehicle is missing required fields and cannot be published.
vehicle_status_process_required409This status is set by a dedicated process (reserve or sale), not by changing status directly.
vehicle_status_transition_invalid409The requested status transition is not allowed from the vehicle's current status.
vehicle_not_reserved409The vehicle is not currently reserved.
vehicle_already_reserved409The vehicle already has an active reservation.
vehicle_reserve_invalid_status409Only a for-sale vehicle can be reserved.
vehicle_not_sold409The vehicle is not sold, so its handover cannot be completed.
vehicle_not_appraisal409The endpoint is only available for appraisal vehicles.
vehicle_appraisal_invalid_status409The appraisal is not in the right state for this action.
vehicle_appraisal_incomplete409The appraisal needs vehicle details before it can be accepted into stock.
credit_cap_exceeded409An item-linked credit line exceeds what remains creditable on the invoice line it references.
purchase_acquisition_linked409The purchase is linked to a vehicle acquisition (the dashboard's vehicle-purchase flow) and cannot be edited via the API - manage it from the dashboard.
invoice_not_issued409The action needs an issued or paid invoice (e.g. generating the finance provider invoice for a draft - issuing the draft does that automatically).
finance_invoice_exists409The invoice already has a finance provider invoice; the message names its number.
invoice_fully_credited409The invoice has been fully credited, so the action is no longer available.

Operation Failed

The request was accepted but the underlying action did not complete. 422 means the input was usable but the operation was rejected; 5xx means a server or upstream-provider failure, safe to retry with backoff.

CodeHTTPMeaning
appointment_contact_not_found422The contact referenced when booking the appointment could not be found.
lead_send_failed422The lead reply could not be sent.
vehicle_lookup_failed422The third-party vehicle lookup (DVLA/DVSA/AutoTrader) failed.
vehicle_recognition_failed422Vehicle/number-plate recognition failed.
vehicle_drive_photo_failed422The test-drive photo could not be stored.
vehicle_media_edit_failed422The media edit could not be applied.
vehicle_media_upload_failed422The media upload could not be processed.
vehicle_costs_full422The vehicle already holds the maximum number of purchase cost rows (50), so the additional-cost link cannot be attached.
finance_invoice_ineligible422The invoice is missing what the finance provider invoice needs: a finance provider contact, a finance amount above zero and a sold vehicle line.
description_failed500AI advert description generation failed.
document_send_failed500The document could not be sent.
appointment_notify_failed500The appointment notification could not be sent.
contact_login_email_failed500The login-details email could not be sent.
contact_login_password_unavailable500A new login password could not be generated.
vehicle_drive_email_failed502The test-drive terms email failed at the mail provider.

Rate Limiting & Server

Throttling and unexpected server conditions. Honour Retry-After on 429; retry 5xx with exponential backoff.

CodeHTTPMeaning
rate_limited429The per-business request rate limit was exceeded. Retry after the window (see Retry-After and X-RateLimit-Reset).
internal500An unexpected server error occurred (503 is returned during maintenance or overload).
internal_error500An unexpected internal error occurred while completing the request (safe to retry with backoff).