Boats

The primary data surface. Both endpoints require the boats.read scope.

GET /v1/boats

Returns a page of boat summaries.

curl -s "https://api.theboatdb.com/v1/boats?manufacturer=albin-marine&sort=year&order=desc" \
-H "Authorization: Bearer $THEBOATDB_API_KEY"

Query parameters

ParameterTypeNotes
manufacturersluge.g. albin-marine
typeslugBoat type, e.g. sail, power
categorysluge.g. cruiser-racer-boats
activitysluge.g. day_cruising
yearFrom, yearTo1800–2100Production-window overlap — see below
lengthMin, lengthMaxnumberExpressed in lengthUnit
lengthUnitm, ftUnit of your length bounds. Default m
search2–100 charsTerm-prefix match on model name
sortmodel, year, length, manufacturerDefault model
orderasc, descDefault asc
limit, offsetintegerlimit max 100, default 20

Any other parameter is a 400. See Conventions.

Filtering by year

Year filtering is overlap-based, not a filter on the first year of production. A boat built from 1971 to 1982 matches ?yearFrom=1975, because it was in production then.

  • A boat with no recorded last year is treated as still in production, so it matches any yearTo.
  • A boat with no recorded first year is excluded as soon as you set either bound — there is nothing to compare it against, and including it would mean returning boats we cannot confirm match.

Filtering by length

Our catalogue stores each boat's measurements in the system its manufacturer published, so lengths are a mix of metres and feet. You do not have to care:

cURL
# Boats between 8 and 12 metres
curl -s "https://api.theboatdb.com/v1/boats?lengthMin=8&lengthMax=12" -H "Authorization: Bearer $KEY"

# The same range, expressed in feet
curl -s "https://api.theboatdb.com/v1/boats?lengthMin=26&lengthMax=40&lengthUnit=ft" -H "Authorization: Bearer $KEY"

Your bound is converted to both systems and each boat is compared against the one matching its own declared unit.

lengthUnit describes your bounds. It is not a filter on the boat's own unit, and it does not change the units in the response — measurements always come back as stored, with unit telling you which system they are in.

sort=length orders on a normalised metre value, so a mixed-unit catalogue sorts as one sequence rather than interleaving 30-foot and 30-metre boats.

Response

data is an array of boat summaries:

JSON
{
  "data": [
    {
      "id": "boat-3f9c1a",
      "slug": "albin-vega-27",
      "model": "Vega 27",
      "version": null,
      "manufacturer": {
        "id": "mfr-71b0",
        "name": "Albin Marine",
        "slug": "albin-marine",
        "website": "https://example.com"
      },
      "type": { "id": "type-sail", "name": "Sail", "slug": "sail" },
      "production": { "firstYear": 1966, "lastYear": 1979 },
      "unit": "metric",
      "lengthOverall": 8.25,
      "lengthOverallMetres": 8.25,
      "referencePrice": { "amount": 12000, "currency": { "code": "EUR", "symbol": "€" } },
      "image": {
        "url": "https://cdn.sanity.io/images/...",
        "alt": null,
        "width": 1600,
        "height": 1067,
        "format": "jpg"
      }
    }
  ],
  "pagination": { "total": 1482, "limit": 20, "offset": 0 }
}
FieldTypeNotes
idstringStable across renames. Store this, not the slug.
slugstringReadable identifier, also accepted by the detail endpoint.
modelstring
versionstring | nullVariant name, where the model has one.
manufacturerobject | nullThin reference: id, name, slug, website.
typeobject | nullid, name, slug.
productionobjectfirstYear and lastYear, either of which may be null.
unitmetric | imperialWhich system the measurements are in.
lengthOverallnumber | nullIn the system unit declares.
lengthOverallMetresnumber | nullAlways metres. The comparable length.
referencePriceobject | nullamount plus currency.code and currency.symbol.
imageobject | nullurl, alt, width, height, format.

GET /v1/boats/:idOrSlug

Returns one boat in full, addressable by slug or id.

curl -s "https://api.theboatdb.com/v1/boats/albin-vega-27" \
-H "Authorization: Bearer $THEBOATDB_API_KEY"

Takes no query parameters?fields=model is a 400, not a partial response. An unknown or unpublished boat is a 404 NOT_FOUND.

Response

Everything in the summary above, plus the full specification grouped by subject:

GroupContains
descriptionPlain text, or null when no published description exists
categoriesArray of id/name/slug references
activitiesArray of id/name/slug references
hulltype, material, keelType, unsinkable, trailerable, appendages
dimensionsLengths, beams, drafts, headroom, displacement, ballast, tonnage
accommodationcabins, berths, heads
steeringhelm, rudder, cockpitType, cockpitLocation
performancecruisingSpeed, topSpeed, displacementHullSpeed
rigMast height and configuration, rigging, spars, spreaders
sailsupwindArea, downwindArea, and name/value entries for mainsail, headsail and spinnaker
tanksCapacities for fuel, water, holding and waterHeaters
enginesArray of maker, model, type, drive, fuel, power, powerType
designersnaval, interior and exterior, each an array of id/name/website
ceClassificationLevels for classes ad, or null if unclassified
galleryArray of images, same shape as image

Engine power and tank capacities are strings, not numbers. Real values include "2 x 40" for a twin-engine installation, and coercing that to a number would silently misreport the boat. Parse them as text.

Any specification we do not hold for a given boat is null rather than omitted, so the shape of the object does not change between boats. description is only populated once an editor has published it — a work-in-progress description reads as null here rather than shipping early.