Charter Boats
Charter Boats API
Boats

Import Boat

Import a boat listing with images

Same in API v1.0 and v1.1

POST/import/boat

Import a new boat listing in a single API call. Handles creating the boat, storing image URLs, and auto-matching to a marina location. The boat is created unpublished — see Publishing.

Boat already on Boataround? You do not need to call this yourself: our Chrome extension imports your own Boataround listing with your API key in one click. See Import your boat from Boataround.

Authentication

Requires API key in the X-API-Key header.

  • Your API key: the boat is created under a company you belong to — one you own, when you own one. If you belong to none, the request fails with 400 ("Create your company in the dashboard first") and nothing is created. owner_id/owner_email are ignored. To target a specific company, pass company_id — you must be a member of it, or the request fails with 403.
  • Platform key (internal): requires owner_id or owner_email in the request body to identify who the boat belongs to. Only the platform key creates a personal "…'s Fleet" company, for an owner who belongs to none.

Every field is checked before anything is written: a request that fails with 400 creates no boat, company, owner, make or location.

X-API-Key: YOUR_API_KEY
Content-Type: application/json

Request Body

Required Fields

FieldTypeDescription
titlestringBoat name/title
boat_typestringOne of: catamaran, sailboat, yacht, motorboat, gulet, rib, other. Optional when model (with manufacturer_id or manufacturer_name) names a model we already know the type of — the boat then takes that model's type; a type you send always wins
capacityintegerMaximum guests (must be at least 1)

Optional Fields

FieldTypeDefaultDescription
descriptionstringFull description, as plain text. Line breaks are kept; HTML and markdown are shown as typed, not rendered
price_per_daynumberDaily rate, returned as price_from (the boat's price_per_day is computed later from its seasons, and stays null until it has one).
length_ftnumberLength overall (LOA) in feet. Values outside the plausible hull range (~6.5–350 ft) are stored as no length rather than as sent — only boats priced from a connected platform take their length from the model catalogue.
yearintegerYear built
cabinsintegerNumber of cabins
berthsintegerNumber of berths
toiletsintegerNumber of toilets
modelstringBoat model name, stored as sent
manufacturer_idstringAn existing make's id, as GET /api/manufacturers lists it; used as sent, ahead of manufacturer_name. An id that names no make fails the request with 400
manufacturer_namestringThe make. Matched on its slug (the name lowercased, non-alphanumerics turned into -), then on the exact name ignoring case, then on the make's known aliases — so send the name as GET /api/manufacturers lists it. A name that matches no existing make creates a new one, and boats under a stray make don't answer the site's make filter for the real one.
rental_typestringbareboatbareboat, skippered, or no_licence_needed
security_depositnumberSecurity deposit amount
skipperinteger|null0 = no skipper, 1 = always skippered, null = skipper is an optional add-on
mmsiintegerThe boat's MMSI, for AIS tracking
flespi_imeistringIMEI of the boat's tracking modem
flespi_modem_modelstringModel of the boat's tracking modem
instant_bookbooleanfalseAllow instant booking
charter_dayintegerCharter start weekday (0=Sun … 6=Sat), stored as sent
check_in_periodsarrayCheck-in/out windows, stored as sent — the shape Get Boat returns (dateFrom, dateTo, checkInDays, checkOutDays, checkInTime, checkOutTime, minimalReservationDuration)
checkin_timestringCheck-in time (e.g. "17:00"); not sent = to be confirmed
checkout_timestringCheck-out time (e.g. "09:00"); not sent = to be confirmed
is_publishedbooleanfalseRuns the completeness check — see Publishing

Publishing

An imported boat is created unpublished. A listing goes live only when it is complete — a title, a location, a capacity, at least one image, and check-in days (charter_day or check_in_periods). is_published: true runs that completeness check after the images are stored: a complete import is published, an incomplete one stays unpublished. The response's boat.is_published says which.

A missing location, capacity or check-in days can be sent later through Update Boat, which re-runs the same check on every save. Images are not a field of Update Boat: send them with the import, or add them in the dashboard.

Location Fields

The boat is placed on a marina in this order:

  1. location_id. An existing location's id is used as sent. An id that names no location fails the request with 400.
  2. Coordinates. With latitude and longitude, the nearest known location inside a box of roughly ±1 km around the point is used, so send the marina's own coordinates.
  3. New marina. If nothing is that close, a new marina is created at the coordinates, named after location_address. Without one it has no name and is shown by its type ("Marina") — a name is never made up from the city.

A name alone never finds a location: location_address, location_city and location_state only fill in a newly created marina. A boat sent with neither location_id nor coordinates gets no location.

FieldTypeDescription
location_idintegerAn existing location's id, used as sent
location_citystringCity; stored on a newly created marina only
location_statestringCountry; stored as the country of a newly created marina only
location_addressstringMarina name, used to name a newly created marina
latitudenumberGPS latitude
longitudenumberGPS longitude

Deduplication Fields

Both are accepted. When import_source names a platform whose listing IDs we link boats to, import_source_id is that link and is checked for duplicates; for any other platform both are ignored.

FieldTypeDescription
import_sourcestringPlatform name
import_source_idstringThe boat's listing ID on that platform

Owner Identification

FieldTypeDescription
company_idstringAssign to a specific company (overrides auto-detection). With your API key you must be a member of it (403 otherwise)
owner_idstringPlatform key only — ignored with your own API key
owner_emailstringPlatform key only — ignored with your own API key
owner_namestringPlatform key only — ignored with your own API key

Images

Array of image URLs or image objects. The first image is set as primary unless specified otherwise.

{
  "images": [
    "https://example.com/image1.jpg",
    { "url": "https://example.com/image2.jpg", "is_primary": true }
  ]
}
FieldTypeDefaultDescription
imagesarrayImage URLs (strings) or objects with url and optional is_primary
download_imagesbooleanAccepted for older integrations and ignored. Every image is copied to our storage by an hourly job after the import; until then it is shown from your URL, so keep the URL reachable

Equipment

Send equipment as features: an array of canonical slugs or plain names ("wifi", "Air condition"), resolved through the same vocabulary the features search filter uses — see Feature Vocabulary. Terms that resolve to nothing are ignored and counted out of features_added. amenities is accepted as the old spelling of the same array. Equipment can also be edited in the dashboard after import.

Request

curl -X POST https://charter.boats/api/import/boat \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "title": "BALI Catspace - Luxury Catamaran",
    "description": "Beautiful 40ft catamaran with 4 cabins.",
    "boat_type": "catamaran",
    "capacity": 8,
    "price_per_day": 850,
    "length_ft": 40,
    "year": 2023,
    "location_address": "D-Marin Lefkas",
    "location_city": "Lefkada",
    "location_state": "Greece",
    "latitude": 38.8289,
    "longitude": 20.7114,
    "manufacturer_name": "Bali",
    "model": "4.0",
    "rental_type": "bareboat",
    "images": [
      { "url": "https://example.com/exterior.jpg", "is_primary": true },
      "https://example.com/interior.jpg"
    ]
  }'

Response

The boat object carries the fields your dashboard's boat editor reads — specs, location, changeover, booking settings, pricing source and the features slug array — plus slug, price_from and price_per_day, and company, manufacturer and images. Only the most relevant fields are shown below. Store boat.id — the slug in view_url can change when the listing is renamed.

{
  "success": true,
  "duplicate": false,
  "boat": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "slug": "bali-catspace-luxury-catamaran",
    "title": "BALI Catspace - Luxury Catamaran",
    "boat_type": "catamaran",
    "capacity": 8,
    "length_ft": 40,
    "year": 2023,
    "price_from": 850,
    "price_per_day": null,
    "instant_book": false,
    "rental_type": "bareboat",
    "is_published": false,
    "location_id": 11336,
    "company": {
      "id": "company-uuid",
      "name": "Sail Greece",
      "slug": "sail-greece"
    },
    "manufacturer": {
      "id": "c581bcca-cc2c-441c-9b28-4fb22f97fa99",
      "name": "Bali",
      "slug": "bali"
    },
    "images": [
      {
        "id": "img-uuid",
        "boat_id": "550e8400-e29b-41d4-a716-446655440000",
        "url": "https://example.com/exterior.jpg",
        "storage_path": null,
        "is_primary": true,
        "sort_order": 0
      }
    ],
    "features": ["wifi", "air_conditioning"]
  },
  "images_uploaded": 2,
  "images_downloaded": 0,
  "features_added": 2,
  "view_url": "https://charter.boats/boats/bali-catspace-luxury-catamaran"
}

Response Fields

FieldTypeDescription
successbooleanWhether the import succeeded
duplicatebooleantrue if an existing boat was returned (a boat of the same company already carries that listing ID)
boatobjectThe created boat with company, manufacturer and images; on a duplicate, the existing boat with company and images
images_uploadedintegerNumber of image records created (absent on a duplicate)
images_downloadedintegerAlways 0: no image is copied during the request. An image has been copied once its url in Get Boat is stored with us (path starting /boats/) (absent on a duplicate)
features_addedintegerCanonical feature slugs resolved from the features array and stored (absent on a duplicate)
view_urlstringPublic URL of the listing — it serves once the boat is published

Deduplication Behavior

When import_source names a platform whose listing IDs we link boats to and import_source_id is provided:

  • Same company: Returns the existing boat with duplicate: true and nothing is changed — the response is { success, duplicate: true, boat, view_url } only (no image or feature counters)
  • Only another company: Returns 409 Conflict

The check runs before the boat, its images or a new marina are created, so a duplicate adds none of them.

Errors

StatusMessage
400title is required
400boat_type is required
400boat_type is required for this model
400boat_type must be one of: catamaran, sailboat, yacht, motorboat, gulet, rib, other
400capacity is required and must be >= 1
400rental_type must be one of: bareboat, skippered, no_licence_needed
400<field> must be a number
400manufacturer_id not found
400location_id not found
400Create your company in the dashboard first
400Owner identification required: provide owner_id or owner_email
401Invalid API key format
401Invalid API key
403You are not a member of the specified company
409This boat has already been imported by another company
500Failed to create company: …
500Failed to create boat: …

A request with no key at all is stopped by bot protection before it reaches this endpoint (an HTML 403 page).

On this page