DealerDMS API · v1

Build on your dealership's live inventory.

A simple, key-authenticated REST API for your stock, semantic search, media and the AI sales assistant. Read the docs freely — you'll create keys inside your DealerDMS account.

Quickstart

Every request is authenticated with a secret API key sent as a Bearer token. Keys are scoped to a single dealership and only ever return that dealership's active data.

  1. Sign in to your DealerDMS account and open Admin & Settings → API Keys.
  2. Create a key and copy it — the secret is shown once.
  3. Call the API with Authorization: Bearer ddms_live_…
# List your active inventory
curl "https://app.car-search.ai/api/v1/inventory?limit=5" \
  -H "Authorization: Bearer ddms_live_YOUR_KEY"

🔒 API keys are only available to signed-up dealerships. Reading these docs is open to everyone; creating keys requires a DealerDMS account with the admin.manage permission.

Base URL

All endpoints are served under /api/v1 on your DealerDMS host:

https://app.car-search.ai/api/v1

Responses are JSON. Requests and responses use UTF-8. List endpoints return a pagination object with offset, limit, total_results and total_pages.

Authentication

Send your key in the Authorization header as a Bearer token. An X-API-Key header is also accepted. Keys are prefixed ddms_live_; the full secret is shown only once at creation and is stored on our side as a SHA-256 hash — we can never show it to you again.

Authorization: Bearer ddms_live_9f2c…
# — or —
X-API-Key: ddms_live_9f2c…
StatusMeaning
401Missing, malformed, invalid or revoked key
403Key lacks the required scope, or the request origin/IP isn't allow-listed for the key
429Per-minute rate limit exceeded (see Rate limits)

Scopes

Each key carries a set of scopes. A request is rejected with 403 if the key doesn't hold the scope the endpoint requires. A key with the * scope may call any endpoint.

ScopeGrants
inventory.readRead inventory, individual vehicles and vehicle images
searchSemantic + text search over inventory
widget.chatEmbedded AI assistant: config + chat turns
*All of the above

Rate limits & security

  • Rate limit. Each key has a per-minute request limit (default 120/min). Exceeding it returns 429 with a Retry-After: 60 header.
  • Origin allow-list. A key may be restricted to specific browser origins (CORS). Requests from other origins get 403.
  • IP allow-list. A key may be restricted to specific server IP addresses for backend-to-backend use.
  • Tenant isolation. A key can only ever read the data of the dealership that owns it.

Endpoints

GET/api/v1/inventoryinventory.read

List the dealership's active inventory, newest first.

Query parameters

offsetRow to start at. Default 0.
limitPage size, max 100. Default 24.
stock_statusFilter by status, e.g. in_stock, reserved, sold.
qFree-text filter (make, model, etc.).
{
  "data": [ { "vehicle_uid": "…", "make": "BMW", "model": "X5", "price": 42995, … } ],
  "pagination": { "offset": 0, "limit": 24, "total_results": 6, "total_pages": 1 }
}
GET/api/v1/inventory/:idinventory.read

Fetch one vehicle by its vehicle_uid, including its image list. Returns 404 if the vehicle isn't found in your dealership.

{ "data": { "vehicle": { … }, "images": [ { "image_uid": "…", … } ] } }
GET/api/v1/images/:imageId/:sizeinventory.read

Serve a vehicle image binary — drop it straight into an <img> on your site. :size is thumb, medium or full. Cached for 24h.

<img src="https://app.car-search.ai/api/v1/images/IMAGE_UID/medium">

Because <img> can't send an Authorization header, images are best served through a key whose origin allow-list includes your website, or proxied by your own backend.

GET/api/v1/widget/configwidget.chat

Public branding + greeting for the embedded AI assistant: assistant name, welcome message, primary colour and logo.

{ "enabled": true, "assistant_name": "Assistant",
  "welcome_message": "Hi! How can I help you find your next car?",
  "primary_color": "#1d4ed8", "logo_url": null }
POST/api/v1/widget/chatwidget.chat

Send one chat turn to the AI sales assistant. It can search your live stock and answer buyer questions. Pass back the conversation_uid it returns to continue a thread.

{ "message": "Do you have any diesel estates?",
  "conversation_uid": null, "visitor_id": "abc-123", "history": [] }
POST/api/v1/widget/chat/streamwidget.chat

Same as /widget/chat, but streams the reply token-by-token as Server-Sent Events for a live typewriter. Same request body. The response is text/event-stream; each data: line is one JSON event:

{ "type": "meta",  "conversation_uid": "…" }   // once, first
{ "type": "delta", "text": "Yes — we have " }   // repeated: reply chunks
{ "type": "tool",  "name": "search_inventory" } // a stock search is running
{ "type": "done",  "reply": "…full text…", "conversation_uid": "…" }
{ "type": "error", "error": "…" }               // only on a mid-stream failure

A rejection that happens before the stream opens (disabled assistant, over a limit) returns a normal JSON error + status instead of a stream. The drop-in widget.js uses this endpoint automatically and falls back to /widget/chat where streaming isn't available.

GET/embed/pubkeypublic

The platform's Ed25519 public key (JWK). Marketplace widget bundles served at /widgets.wc.js carry an X-DDMS-Signature (base64 Ed25519 over the exact bytes) and an X-DDMS-Key-Id. Verify the signature before executing the bundle to guarantee it wasn't tampered with in transit or at a CDN:

const base = 'https://app.car-search.ai';
const [{ x }, res] = await Promise.all([
  fetch(base + '/embed/pubkey').then(r => r.json()),
  fetch(base + '/widgets.wc.js'),
]);
const bytes = new Uint8Array(await res.clone().arrayBuffer());
const sig = Uint8Array.from(atob(res.headers.get('X-DDMS-Signature')), c => c.charCodeAt(0));
const key = await crypto.subtle.importKey('jwk',
  { kty: 'OKP', crv: 'Ed25519', x }, { name: 'Ed25519' }, false, ['verify']);
if (!await crypto.subtle.verify('Ed25519', key, sig, bytes))
  throw new Error('bundle failed signature verification');
await import(URL.createObjectURL(new Blob([bytes], { type: 'application/javascript' })));

Errors

Errors return the appropriate HTTP status and a JSON body of the shape { "error": "…" }. Handle 401/403 (auth), 404 (not found), 429 (back off using Retry-After) and 5xx (retry with backoff).

Managing API keys

API keys are created and revoked inside your DealerDMS account — only signed-up dealerships can hold keys, and only a user with the admin.manage permission can manage them.

  1. Sign in and go to Admin & Settings → API Keys.
  2. Click New API key, name it (e.g. "Website"), and choose scopes.
  3. Copy the ddms_live_… secret immediately — it is shown once.
  4. Optionally restrict the key to specific origins/IPs and set a rate limit.
  5. Revoke a key any time; it stops working instantly.

Sign in to manage keys →

Not a DealerDMS customer yet?

Get access to the API — and the whole platform — by booking a demo.

Request a demo