Website themes
Dealers on a paid plan can ask Vehiso's AI theme builder for a new look for their website, from their own tools, exactly as they can from the DMS. You describe the theme in a brief, the builder makes it in the background, and you publish the result when you are happy with it. A build never goes live by itself.
| Scope | Allows |
|---|---|
website_themes:read | Read theme builds and theme versions |
website_themes:write | Request builds and publish versions |
Both need the key's owner to hold the website.theme permission in the DMS.
The flow
- Request a build with
POST /v1/theme-generations. It answers202with a generation whosestatusisqueued. - Follow it by polling
GET /v1/theme-generations/{id}, or with webhooks. The status moves fromqueuedtorunning, and ends assucceededorfailed. - Preview it. A succeeded generation carries the theme
versionit built and, on the GET, apreview_url. - Publish it with
POST /v1/theme-versions/{version}/publish.
1. Request a build
Send a brief describing the theme. You can add a reference_url for a website to take the look from. Set reference_content_consented to true only if the dealer may use that site's content, not just its style.
curl https://api.vehiso.com/v1/theme-generations \
-H "Authorization: Bearer $VEHISO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6a1d3e8f-2b4c-4d5e-9f7a-0b1c2d3e4f5a" \
-d '{"brief": "Dark, understated premium look for a used prestige car dealer. Large photography, minimal text, gold accents."}'
{
"data": {
"id": "0e4b2f6a-9c3d-4a1e-8b7f-5d2c1a0e9f84",
"kind": "generate",
"status": "queued",
"brief": "Dark, understated premium look for a used prestige car dealer. Large photography, minimal text, gold accents.",
"instruction": null,
"reference_url": null,
"version": null,
"findings": [],
"failure_reason": null,
"created_at": "2026-09-27T14:02:11Z",
"finished_at": null
}
}
To change the latest theme rather than start again, send "kind": "revise" with an instruction instead of a brief:
{"kind": "revise", "instruction": "Make the header smaller and use the dealer's blue for buttons."}
Each dealer has a monthly allowance of builds. Send an Idempotency-Key so a retried request does not spend a second one.
2. Follow the build
- Node.js
- Python
const headers = {Authorization: `Bearer ${process.env.VEHISO_API_KEY}`};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export async function waitForTheme(generationId) {
for (;;) {
const res = await fetch(`https://api.vehiso.com/v1/theme-generations/${generationId}`, {headers});
const {data} = await res.json();
if (data.status === 'succeeded' || data.status === 'failed') return data;
await sleep(10000);
}
}
import os
import time
import requests
HEADERS = {"Authorization": f"Bearer {os.environ['VEHISO_API_KEY']}"}
def wait_for_theme(generation_id):
while True:
res = requests.get(
f"https://api.vehiso.com/v1/theme-generations/{generation_id}",
headers=HEADERS,
timeout=30,
)
data = res.json()["data"]
if data["status"] in ("succeeded", "failed"):
return data
time.sleep(10)
A build takes a while, so poll every few seconds at most. Instead of polling, you can subscribe a webhook endpoint to theme_generation.started, theme_generation.succeeded and theme_generation.failed. The events carry the generation in data.object, and they fire for every build, whether it was requested through the API, in the DMS or by the assistant.
A failed generation says why in failure_reason: quota, entitlement or generation_failed.
3. Preview it
Once a generation has succeeded, version is the theme version it built, and findings lists any lint findings on it (each with a severity of error or warning, a path, a line and a message).
GET /v1/theme-generations/{id} also returns a preview_url: a signed link that shows the new version on the dealer's site before it goes live. It expires after 30 minutes, so fetch the generation again for a fresh link rather than storing it.
GET /v1/theme-versions lists every version, generated or uploaded, with a count of its findings and which one is live. Unlike other lists it is paged by number, with page and per_page (up to 100), and meta.last_page and meta.total.
4. Publish it
curl -X POST https://api.vehiso.com/v1/theme-versions/12/publish \
-H "Authorization: Bearer $VEHISO_API_KEY"
{"data": {"version": 12, "is_live": true}}
Publishing refuses a version that is not safe to put live with 422 theme_publish_blocked. errors.routes lists pages the theme does not render, and errors.findings its error-severity lint findings, as path:line: message. Request a revision that fixes them, then publish the new version.
Errors
| Status | code | Meaning |
|---|---|---|
| 403 | theme_builder_not_enabled | The dealer has not turned on the theme builder. Any dealer on a paid plan can turn it on in the DMS under Administration > Feature previews. |
| 403 | plan_not_entitled | The dealer needs a paid plan. |
| 429 | theme_generation_quota_exceeded | This month's builds are used up. This is not a rate limit: there is no Retry-After, and retrying soon will not help. |
| 422 | theme_publish_blocked | The version is missing required pages or has error findings. See above. |
The full request and response bodies are in the API reference.