43,678 bikes · 493 makes Add a bikeLog inRegister

MotorcycleDB API

Read-only access to 43,000+ motorcycle specifications. Every request needs an API key - request one. Use of this API is governed by the API Terms, separate from the site's own Terms & Privacy.

Base URL

https://www.motorcycledb.com/api/v1

Every endpoint below is relative to this - e.g. GET /bikes means GET https://www.motorcycledb.com/api/v1/bikes.

Authentication

Send your key on every request, either as a Bearer token or in an X-Api-Key header:

Authorization: Bearer mdb_your_key_here
X-Api-Key: mdb_your_key_here

Requests without a valid key return 401.

Limits

Paid plans have a monthly request limit that resets on your billing date each month; unused requests don't carry over. Trial keys have a fixed number of requests in total. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining, and paid keys also get X-RateLimit-Reset (UTC, when the next month starts). Once a Builder or Business plan's limit is reached, booster credits are used automatically and X-Booster-Credits-Remaining shows what is left.

Every call counts as one request, except a detail=full search, which counts one request per bike returned (a page of 50 complete bikes is 50 requests). A summary search counts as one request whatever its page size. If a detail=full page would cost more than you have left, it returns 429 insufficient_requests and only the call itself is counted (one request): lower per_page and try again.

Machine-readable spec and code examples

An OpenAPI 3 description of every endpoint and field is at /api/v1/openapi.json (no key needed) - import it into Postman, Insomnia or a client generator.

Python (pip install requests):

import requests

r = requests.get(
    "https://www.motorcycledb.com/api/v1/bikes",
    headers={"X-Api-Key": "mdb_your_key_here"},
    params={"q": "mt09", "year_min": 2021, "detail": "full"},
    timeout=10,
)
r.raise_for_status()
for bike in r.json()["data"]:
    print(bike["model"], bike["year"], bike["spec"]["performance"]["power_hp"], "hp")

JavaScript (browser or Node 18+; keep your key on the server):

const url = new URL("https://www.motorcycledb.com/api/v1/bikes");
url.search = new URLSearchParams({ make: "Ducati", category: "Naked", sort: "-year" });

const res = await fetch(url, { headers: { "X-Api-Key": process.env.MDB_API_KEY } });
if (!res.ok) throw new Error((await res.json()).error.message);
const { data, meta } = await res.json();
console.log(`${meta.total} bikes`, data.map(b => `${b.model} ${b.year}`));

GET /api/v1/bikes

Search/list bikes. Query parameters (all optional, combine freely):

ParameterDescription
qFree-text make + model search. Ignores spaces and hyphens (mt09 finds MT-09); several words must all match (yamaha r1 finds YZF-R1). A model year, seat height (under 750mm seat), engine size (over 600cc) or a category on its own (naked 2024) in q fills that filter when you haven't set it; meta.interpreted shows what was taken out
makeManufacturer. An exact name (any case) if one exists, otherwise a partial match: Harley finds Harley-Davidson
modelModel name, partial, ignoring spaces and hyphens
year, year_min, year_maxExact model year, or a range
categoryCategory name, any case, e.g. Naked, Adventure - full list at /categories. An unknown name returns 400 with the valid values
powertrainice or electric
cc_min, cc_maxEngine capacity range, cc
hp_min, hp_maxPower range, hp
abstrue = ABS fitted as standard
seat_height_maxMaximum seat height in mm
seat_height_minMinimum seat height in mm
sortid (default), name, year, capacity_cc, power_hp, seat_height_mm or popularity. Prefix - for descending, e.g. -popularity for most-viewed first. Bikes without the value sort last
detailsummary (default, the fields below) or full: every result comes with its typed spec, description and dates, as in /bikes/{id}
pageDefault 1
per_pageDefault 20, max 100 (max 50 with detail=full, each bike counting as one request)
curl -H "X-Api-Key: mdb_your_key_here" \
  "https://www.motorcycledb.com/api/v1/bikes?q=mt09&year=2024"
{
  "data": [
    { "id": 66877, "make": "Yamaha", "model": "Yamaha MT-09 SP", "year": 2024,
      "category": "Naked", "capacity_cc": 890, "power_hp": 119,
      "seat_height_mm": 820, "url": "https://www.motorcycledb.com/yamaha/mt09sp/2024/",
      "image_url": "https://www.motorcycledb.com/images5/Yamaha/Yamaha-MT-09-55451.webp",
      "thumb_url": "https://www.motorcycledb.com/images5/Yamaha/Yamaha-MT-09-55451-thumbnail.webp" },
    { "id": 67350, "make": "Yamaha", "model": "Yamaha MT-09", "year": 2024,
      "category": "Naked", "capacity_cc": 890, "power_hp": 117.4,
      "seat_height_mm": 825, "url": "https://www.motorcycledb.com/yamaha/mt09/2024/",
      "image_url": "https://www.motorcycledb.com/images/Yamaha/Yamaha-MT-09-33262.webp",
      "thumb_url": "https://www.motorcycledb.com/images/Yamaha/Yamaha-MT-09-thumb-33262.webp" }
  ],
  "meta": { "page": 1, "per_page": 20, "total": 2, "total_pages": 1 }
}

GET /api/v1/bikes/{id}

Everything on record for one bike:

Fixed codes: powertrain ICE/Electric; engine_cycle 2/4 (stroke); cooling air/oil_air/liquid; transmission manual/automatic; abs_type yes/dual_channel/switchable/optional/unspecified.

curl -H "X-Api-Key: mdb_your_key_here" \
  "https://www.motorcycledb.com/api/v1/bikes/61964"
{
  "data": {
    "id": 61964, "make": "Yamaha", "model": "Yamaha YZF-R1", "year": 2020,
    "url": "https://www.motorcycledb.com/yamaha/yzf-r1/2020/",
    "image_url": "https://www.motorcycledb.com/images/Yamaha/Yamaha-YZF-R1-33511.webp",
    "thumb_url": "https://www.motorcycledb.com/images/Yamaha/Yamaha-YZF-R1-thumb-33511.webp",
    "photos": [
      { "url": "https://www.motorcycledb.com/images/Yamaha/Yamaha-YZF-R1-33511.webp",
        "thumb_url": "https://www.motorcycledb.com/images/Yamaha/Yamaha-YZF-R1-thumb-33511.webp" }, ...
    ],
    "description": "The 2020 Yamaha YZF-R1 is a track-focused superbike ...",
    "notable_features": null,
    "spec": {
      "category": "Sport", "category_2": null,
      "engine": { "powertrain": "ICE", "capacity_cc": 998, "engine_config": "In-line", "cylinders": 4,
                  "engine_cycle": 4, "bore_mm": 79, "stroke_mm": 50.9, "compression_ratio": 13,
                  "valves_per_cyl": 4, "cooling": "liquid", "fuel_system": "injection", ... },
      "performance": { "power_hp": 200, "power_kw": 146, "power_rpm": 13500,
                       "torque_nm": 112.4, "torque_rpm": 11500, "top_speed_kmh": 270, ... },
      "electric": { "motor_kw": null, "battery_kwh": null, "range_km": null, ... },
      "drivetrain": { "transmission": "manual", "gear_count": 6, "final_drive": "chain", ... },
      "chassis": { "front_brake_mm": 320, "abs_type": "yes", "front_tyre": "120/70-ZR17",
                   "rake_deg": 24, "trail_mm": 102, ... },
      "dimensions": { "seat_height_mm": 856, "wheelbase_mm": 1405, "wet_weight_kg": 203.2, ... },
      "fuel": { "fuel_capacity_l": 17, "fuel_consumption_l100": 6.9, "co2_gkm": 161, ... },
      "other": { "warranty_months": 12, "colour_options": "Yamaha Blue, Rapid Red" }
    },
    "updated_at": "2026-09-29", "verified_at": null,
    "character_profile": {
      "scores": { "speed": 100, "agility": 83, "comfort": 28, "offroad": 2, "touring": 22, "road": 72 },
      "fit_for": { "track": 99, "city": 30, "cornering": 96, "daily": 28, "touring": 22, "passenger": 18 },
      "best_for": "...", "built_for": "...", "not_ideal_for": "...",
      "note": "Editorial estimate derived from the spec sheet using the same model for every bike - not lab tested."
    }
  }
}

GET /api/v1/categories

Every category name /bikes?category= accepts, most common first, with bike counts.

{ "data": [ { "name": "Naked", "bike_count": 9227 }, { "name": "Scooter", "bike_count": 8703 }, ... ] }

GET /api/v1/makes

Paginated manufacturer list. q filters by name (partial, ignoring spaces and hyphens) - the quick way to find a make's id.

curl -H "X-Api-Key: mdb_your_key_here" "https://www.motorcycledb.com/api/v1/makes?q=yamaha"
{
  "data": [
    { "id": 4116, "name": "Yamaha", "model_count": 3602, "url": "https://www.motorcycledb.com/yamaha/" }
  ],
  "meta": { "page": 1, "per_page": 20, "total": 1, "total_pages": 1 }
}

GET /api/v1/makes/{id}/models

Models for one manufacturer - one entry per model, spanning all its production years.

curl -H "X-Api-Key: mdb_your_key_here" "https://www.motorcycledb.com/api/v1/makes/4116/models?per_page=1"
{
  "data": [
    { "name": "Yamaha FZ1-S Fazer", "year_from": 2006, "year_to": 2016,
      "model_years_on_record": 11, "url": "https://www.motorcycledb.com/yamaha/fz1s-fazer/" }
  ],
  "meta": { "page": 1, "per_page": 1, "total": 850, "total_pages": 850 }
}

GET /api/v1/recalls

Safety recall lookup (US NHTSA campaigns). Query parameters: make (exact), model (partial), year, page, per_page.

curl -H "X-Api-Key: mdb_your_key_here" "https://www.motorcycledb.com/api/v1/recalls?make=Can-Am&per_page=1"
{
  "data": [
    { "campaign_number": "26V575000", "component": "ELECTRICAL SYSTEM: INSTRUMENT CLUSTER/PANEL",
      "summary": "...", "consequence": "...", "remedy": "...", "report_date": "2026-09-07",
      "bike": { "id": 71815, "make": "Can-Am", "model": "Can-Am Spyder F3", "year": 2024,
                "url": "https://www.motorcycledb.com/can-am/spyder-f3/2024/" } }
  ],
  "meta": { "page": 1, "per_page": 1, "total": 60, "total_pages": 60 }
}

GET /api/v1/vin/{vin}

Decode a VIN and, when it matches something in our catalog, get the direct link to it. Full 17-character VINs and partial VINs (at least the first 8 characters) both work. Decoded entirely from locally-held NHTSA vPIC data - coverage is US-market motorcycles only, and not every decoded make/model has a matching catalog page yet (match is null in that case, which is a normal outcome, not an error). When there is a match, match holds its level, make, model, exact_year_matched and url.

curl -H "X-Api-Key: mdb_your_key_here" \
  "https://www.motorcycledb.com/api/v1/vin/1HD1KB4177Y653770"
{
  "data": {
    "vin": "1HD1KB4177Y653770", "make": "Harley-Davidson", "model": "Street Glide",
    "model_year": 2007, "model_year_confident": true, "match": null
  }
}

Errors

Every error has the same shape:

{ "error": { "code": "rate_limit_exceeded", "message": "Monthly limit of 25000 requests reached and no booster credits left. ..." } }
HTTPcodeMeaning
400invalid_category, invalid_sort, invalid_detail, invalid_powertrain, invalid_abs, invalid_cc_min (etc.), missing_vin, invalid_vinA parameter isn't valid - the message says what is accepted
401missing_api_key, invalid_api_keyNo key sent, or the key isn't recognised
403revoked_api_keyThe key has been revoked
403trial_usedA trial key has used all its requests
403no_active_planThe key's plan has ended - choose a plan on your account page
404not_foundNo bike/make with that id, or a VIN that can't be decoded
429rate_limit_exceededOver the plan's monthly limit with no booster credits left
429insufficient_requestsA detail=full page would cost more requests than you have left (only the call itself was counted)