Send the key
Keys look like otp_live_…. Send one as a Bearer token, or in x-api-key if your HTTP client cannot set Authorization. Both are accepted on every route; pick one and keep it out of query strings and logs.
curl 'https://vinspeclookup.com/api/v1/fluids?vin=5J6RW2H82KL000007' \ -H 'Authorization: Bearer otp_live_…'# or, the same call with the plain headercurl 'https://vinspeclookup.com/api/v1/fluids?vin=5J6RW2H82KL000007' \ -H 'x-api-key: otp_live_…'A request with no key, an unknown key, or a revoked key returns 401 invalid_api_key. A key without the scope a route needs returns 403 insufficient_scope. Both bodies have the same two fields as every other error, described on Errors.
No key yet: the sandbox
Every read route is mirrored at https://vinspeclookup.com/api/sample with no authentication, rate-limited to 30 requests per minute per IP address. Responses have the exact shape of the live API for the reference vehicle, so you can build the integration first and paste a key later.
curl 'https://vinspeclookup.com/api/sample/v1/fluids?config_key=2019_honda_cr_v_ex_l15be'The sandbox is read-only. The only write, POST /v0/enrich, answers 403 write_disabled there. Keys are issued by hand while OtoIndex is pre-launch: use the request access form.
Scopes
A key carries scopes. Free keys carry maintenance:read, labor:read and media:read; service_history:read and enrich:write come with paid plans. The scope a route needs is listed on each operation in the reference and repeated here.
| Scope | Grants | Endpoints |
|---|---|---|
maintenance:read | Identity, fluids, spec sheet, tires, service intervals, parts and prices | /v1/decode, /v1/configs, /v1/vehicle, /v1/fluids, /v1/specs, /v1/tires, /v1/maintenance-schedule, /v1/parts, /v0/maintenance |
labor:read | Labor time estimates | /v0/labor |
media:read | The cached exterior render | /v0/vehicle-image |
service_history:read | Sanitized per-VIN service history | /v0/service-history |
enrich:write | Schedule enrichment for a VIN we do not hold yet (Pro and Scale) | POST /v0/enrich, GET /v0/enrich |
From a browser
The gateway answers preflights and allows Authorization, Content-Type and x-api-key from any origin, so calls work from a web app. Treat that as a convenience for prototypes: a key in client-side code is a key anyone can read. In production, call the API from your server.
Before you go live
- Keep the key in an environment variable on the server that makes the call. Never in a repository, a mobile bundle, or a query string.
- Build against the sandbox first. It returns the live shape for the reference vehicle, so parsing, error handling and the 409 flow can be finished before a key exists.
- Store the config_key once a VIN has resolved, and use it for every later call. It is stable, exact, and skips the decode.
- Handle 401 and 403 as configuration errors, not retries: a rotated key or a missing scope will not fix itself. Log the error code, not the message.
- To rotate a key while the dashboard is not yet live, ask through the request-access form; a new key is issued and the old one revoked on a date you choose.