API Documentation
Open Labor Project exposes a REST API for automotive labor times, torque specs, fluid capacities, OBD-II DTCs, batteries, parts, and estimates. All endpoints return JSON. Authentication is a single header. Start with a free Hobbyist key, upgrade tiers when you outgrow it.
New here? Start here.
If you've never used an API before, this section walks you through your first successful call — what to click, where to paste, and what success looks like. No assumptions.
Go to openlaborproject.com/developers and request a free Hobbyist key (no credit card needed). You'll get an email with a long string like 12345678-1234-1234-1234-123456789abc — that's your key. Copy it somewhere safe (a sticky note in your password manager is fine for now; we'll show you the professional way to store it later).
A "terminal" is a text-only window where you type commands. Every OS has one built in — you don't need to install anything.
Win + R, type powershell, hit Enter. A dark blue window opens — that's PowerShell. Click in it so you can type.Cmd + Space, type terminal, hit Enter. A small window with a prompt opens.Ctrl + Alt + T on most desktops.Copy the line below, paste it into your terminal, replace YOUR_KEY_HERE with the actual key you got in step 1, then hit Enter.
curl "https://openlaborproject.com/api/v1/labor-times?make=ford&model=f-150&year=2017" -H "x-api-key: YOUR_KEY_HERE"
curl is an alias for a different command and may not handle this exactly right. If you see an error, replace curl with curl.exe — that runs the real curl shipped with Windows 10/11.You should see a wall of JSON dump into the terminal. Don't worry about reading it — if you see "data": and a bunch of jobs like "Brake Pads — Front", congrats, the API works for you. Move on to the code examples and start integrating.
If instead you see one of these:
"code": "MISSING_API_KEY"— you didn't replaceYOUR_KEY_HEREwith your actual key. Go back to step 3."code": "INVALID_API_KEY"— the key is wrong or has a typo. Copy it fresh from the email.- An HTML response (lots of
<tags>) — Cloudflare blocked the request because the header didn't make it through. Check the Windows note above, or jump to Common gotchas. curl: command not found— you're on a really old setup. Use the JavaScript example in Code examples instead.
Quickstart
1. Get a free key at openlaborproject.com/developers (no credit card for Hobbyist).
2. Send a test request:
curl "https://openlaborproject.com/api/v1/labor-times?make=ford&model=f-150&year=2017" \ -H "x-api-key: YOUR_KEY_HERE"
You should get a JSON response with labor times grouped by engine variant. If you get 401 INVALID_API_KEY, double-check the key value. If you get 403 with HTML, you've hit Cloudflare — see Common gotchas.
Authentication
Every request needs an API key passed via one of two headers. Both work identically — pick whichever fits your HTTP client.
x-api-key so our server knows it's you. It is NOT a query parameter (?key=...) and NOT a script tag in HTML.Option A — x-api-key header
x-api-key: 12345678-1234-1234-1234-123456789abc
Option B — Authorization: Bearer
Authorization: Bearer 12345678-1234-1234-1234-123456789abc
The Bearer form is convenient if you're using a generic API client (Postman, Insomnia, an SDK builder) that has a built-in Bearer auth field.
Storing your key safely
The pro move is to put the key in an environment variable on your computer or server, then have your code read it from there. That way the key never appears in your source files — so it can't accidentally end up on GitHub.
OLP_API_KEY so it's obvious what it is.Set the variable (one-time per machine)
# Persistent (survives reboots): [System.Environment]::SetEnvironmentVariable( 'OLP_API_KEY','YOUR_KEY_HERE','User') # Then close and reopen PowerShell. # Verify it stuck: $env:OLP_API_KEY
# Add this line to ~/.zshrc (Mac default) # or ~/.bashrc (most Linux): export OLP_API_KEY="YOUR_KEY_HERE" # Reload your shell: source ~/.zshrc # or ~/.bashrc # Verify: echo $OLP_API_KEY
# Create a file named .env in your project root:
OLP_API_KEY=YOUR_KEY_HERE
# Add ".env" to your .gitignore so it
# never gets committed!
# In your code:
require('dotenv').config();
process.env.OLP_API_KEYThen use it in your code
Once the variable is set, your code reads it without ever knowing the actual key value:
// Node / JavaScript
fetch(url, { headers: { 'x-api-key': process.env.OLP_API_KEY } })
# Python
requests.get(url, headers={'x-api-key': os.environ['OLP_API_KEY']})
# Bash / curl
curl -H "x-api-key: $OLP_API_KEY" "$url"Response shape
Every endpoint returns the same envelope. Success or failure, the three top-level keys are always present.
{
"data": { ... } | null, // the payload on 2xx; null on 4xx/5xx
"meta": {
"timestamp": "2026-06-09T18:00:00.000Z",
// endpoint-specific extras (count, region, rateLimit, etc.)
},
"error": null | {
"code": "MACHINE_READABLE_CODE",
"message": "Human-readable explanation."
}
}Inspect error.code (not the HTTP status alone) to branch on failure mode — codes are stable, messages may evolve.
Error codes
| HTTP | Code | What it means |
|---|---|---|
| 400 | MISSING_PARAMS | Required query param missing. Read the message. |
| 400 | INVALID_YEAR | Year must be YYYY or YYYY-YYYY. |
| 401 | MISSING_API_KEY | No x-api-key or Bearer header sent. |
| 401 | INVALID_API_KEY | Key revoked, malformed, or doesn't exist. |
| 402 | PAYMENT_REQUIRED | Subscription past due. Update payment to restore access. |
| 403 | TIER_LOCKED | Feature requires a higher tier (e.g. webhooks need Business+). |
| 404 | NOT_FOUND | No data for this vehicle/job combination. |
| 405 | METHOD_NOT_ALLOWED | Use GET. All v1 endpoints are GET-only. |
| 429 | RATE_LIMIT_EXCEEDED | Daily limit hit. Resets at midnight UTC. |
| 429 | BURST_LIMIT_EXCEEDED | Per-minute limit hit. See Retry-After header. |
| 500 | INTERNAL_ERROR | Our problem. Retry with backoff. |
Rate limits
Two limits run in parallel: a daily cap (resets midnight UTC) and a per-minute burst cap (resets every full minute). Hitting either returns 429.
| Tier | Daily | Per minute | Price |
|---|---|---|---|
| Hobbyist (testing) | 7 | 10 | Free |
| Builder | 1,000 | 300 | $49/mo |
| Business | 10,000 | 1,000 | $149/mo |
| Enterprise | 50,000+ | 5,000+ | $499+/mo |
Headers returned on every response
X-RateLimit-Tier: builder X-RateLimit-Limit-Daily: 1000 X-RateLimit-Remaining-Daily: 847 X-RateLimit-Reset-Daily: 2026-06-10T00:00:00.000Z X-RateLimit-Limit-Minute: 300 X-RateLimit-Remaining-Minute: 295 Retry-After: 42 # only on 429 BURST_LIMIT_EXCEEDED
Watch Remaining-Daily and back off proactively rather than waiting for a 429. The legacy X-RateLimit-Limit / X-RateLimit-Remaining headers are still sent as daily-value aliases for backward compatibility.
Endpoint reference
All endpoints are GET, hosted at https://openlaborproject.com, and return JSON. Query params are URL-encoded.
Labor hours per repair job for a vehicle.
make, model, yearOptional:engine, job, region/api/v1/labor-times?make=ford&model=f-150&year=2017&engine=3.5l-v6-ecoboostResponse shape
{
"data": {
"vehicle": { "make": "Ford", "model": "F-150", "yearRange": "2017-2017", "engine": "3.5L V6 EcoBoost" },
"laborTimes": [
{ "job": "Brake Pads — Front", "jobSlug": "brake-pads-front", "category": "brakes",
"hours": 1.3, "lowRange": 1.1, "highRange": 1.6, "confidence": "high" },
// ...
]
},
"meta": { "count": 287, "region": "US", "timestamp": "2026-06-09T18:00:00.000Z" },
"error": null
}Torque values for fasteners on a job.
make, model, yearOptional:engine, job, region/api/v1/torque-specs?make=ford&model=f-150&year=2017&engine=3.5l-v6-ecoboost&job=brake-pads-frontResponse shape
{
"data": {
"vehicle": { "make": "Ford", "model": "F-150", "engine": "3.5L V6 EcoBoost" },
"torqueSpecs": [
{ "job": "Brake Pads — Front", "component": "Caliper Bracket Bolt",
"nm": 175, "lbFt": 129, "angleDegrees": null, "sequence": null,
"isCritical": true, "notes": "Use new bolts", "confidence": "oem_verified" }
]
},
"meta": { "count": 4, "region": "US" }
}Fluid types and capacities by system (engine oil, coolant, ATF, etc.).
make, model, yearOptional:engine, region/api/v1/fluid-specs?make=toyota&model=camry&year=2018OBD-II diagnostic trouble codes. Lookup by vehicle or by code.
(make + model + year) OR codeOptional:engine, region/api/v1/dtc-codes?code=P0301 or /api/v1/dtc-codes?make=honda&model=civic&year=2014OE battery group size, CCA, AGM/flooded, replacement specs.
make, model, yearOptional:engine, region/api/v1/battery-specs?make=bmw&model=328i&year=2015Vehicle catalog — list engines/years for a make+model. Discovery helper for getting valid slugs to send to the other endpoints. Returns minimal fields.
make, modelOptional:region/api/v1/vehicles?make=ford&model=f-150Rich engine identification: OEM engine code, fuel type, forced induction, transmission, drivetrain — everything you need to identify the variant beyond NHTSA vPIC.
make, modelOptional:year, region/api/v1/engines?make=ford&model=f-150&year=2017Response shape
{
"data": {
"make": "Ford",
"model": "F-150",
"engines": [
{
"yearStart": 2017, "yearEnd": 2017, "yearRange": "2017",
"engine": "3.5L V6 EcoBoost",
"engineSlug": "3.5l-v6-ecoboost",
"engineCode": "ECOBOOST-35",
"fuelType": "gasoline",
"forcedInduction": "twin-turbo",
"transmission": "automatic",
"drivetrain": "4wd"
}
]
},
"meta": { "count": 4, "region": "US" }
}OE/aftermarket part numbers and price ranges for a job on a vehicle.
make, model, year, jobOptional:engine, region/api/v1/parts?make=ford&model=f-150&year=2017&job=brake-pads-frontCombined labor + parts estimate for a job. Auto-generates labor if missing.
make, model, year, jobOptional:engine, region/api/v1/estimate?make=ford&model=f-150&year=2017&job=brake-pads-frontDigital Vehicle Inspection catalog — every inspection item we track.
(none)Optional:category/api/v1/dvi-items?category=brakesLookup labor/torque/fluid data for a single DVI inspection item on a vehicle.
item, make, model, yearOptional:engine, region/api/v1/dvi-lookup?item=brake-pads-front&make=ford&model=f-150&year=2017Code examples
Same request — labor times for a 2017 Ford F-150 3.5L EcoBoost — in the three most common languages.
cURL
curl "https://openlaborproject.com/api/v1/labor-times?make=ford&model=f-150&year=2017&engine=3.5l-v6-ecoboost" \ -H "x-api-key: $OLP_API_KEY"
JavaScript / Node (fetch)
const res = await fetch(
'https://openlaborproject.com/api/v1/labor-times?make=ford&model=f-150&year=2017&engine=3.5l-v6-ecoboost',
{ headers: { 'x-api-key': process.env.OLP_API_KEY } }
);
if (!res.ok) {
const { error } = await res.json();
throw new Error(`OLP ${error.code}: ${error.message}`);
}
const { data, meta } = await res.json();
console.log(`${data.laborTimes.length} jobs for the ${data.vehicle.engine}`);
// Back off if we're close to the daily cap
const remaining = parseInt(res.headers.get('X-RateLimit-Remaining-Daily'), 10);
if (remaining < 50) console.warn('Approaching daily limit:', remaining);Python (requests)
import os, requests
r = requests.get(
'https://openlaborproject.com/api/v1/labor-times',
params={'make': 'ford', 'model': 'f-150', 'year': 2017, 'engine': '3.5l-v6-ecoboost'},
headers={'x-api-key': os.environ['OLP_API_KEY']},
timeout=15,
)
if r.status_code == 429:
retry = int(r.headers.get('Retry-After', '60'))
raise SystemExit(f'Rate limited, retry in {retry}s')
r.raise_for_status()
data = r.json()['data']
print(f"{len(data['laborTimes'])} jobs for the {data['vehicle']['engine']}")Common gotchas
Cloudflare bot challenge (403 with HTML body)
If you get a 403 response that looks like HTML instead of JSON, you've hit our Cloudflare bot challenge — meaning your request arrived without the API key header. Cloudflare lets anything with a valid x-api-key or Authorization: Bearer header through. Most often: a proxy or SDK stripped the header. Confirm by inspecting the request right before it's sent.
Make and model slugs are lowercase, hyphenated
ford, not Ford. f-150, not F-150 or F150. Pull the slug list from /api/v1/vehicles if you're unsure.
Year can be single or range
year=2017 matches that single model year. year=2015-2020 matches any vehicle whose year range overlaps. Anything else returns 400 INVALID_YEAR.
Engine slug is the canonical form, not a display string
3.5l-v6-ecoboost, not 3.5L V6 EcoBoost. Hit /api/v1/vehicles?make=…&model=… to list engine slugs for a model.
404 NOT_FOUND vs. empty result
We return 404 with NOT_FOUND when the vehicle/job combo has no data — not a 200 with an empty array. Branch on error.code to distinguish "we don't have it yet" from "your request was malformed".
Premium features and grandfathered keys
Some features (advanced filtering, bulk lookup, webhooks, bulk export) require a paid tier and return 403 TIER_LOCKED on Hobbyist. The error payload includes feature and required_tier so you can prompt an upgrade.