1. Docs

Developer Documentation

Adflow API

Integrate live boat listings directly on your website. Choose between the Direct Feed from the app server or the Edge Feed served globally via Cloudflare Workers.

Two options

Choose your integration

Direct Feed

app.yachtmaster.cloud

Pull data directly from the app server. Best for server-side rendering or scheduled syncs where you cache the data yourself.

  • Real-time data, straight from the database
  • Supports incremental sync via ?since=
  • No setup required beyond your feed token
GET app.yachtmaster.cloud/feed/:token

Edge Feed

ads.yachtmaster.cloud

Cached and served globally via Cloudflare Workers. Best for browser-side JavaScript, static sites, or anywhere CORS and low latency matter.

  • CORS enabled — call directly from the browser
  • Served from the nearest Cloudflare edge node
  • Single ad lookup via /v1/ads/:token/:id
GET ads.yachtmaster.cloud/v1/ads/:token
Step 1

Get your feed token

Your feed token is a unique UUID that identifies your company's listing feed. It is found in Settings → Adflow inside the YachtMaster app.

The token is included in the URL — anyone with it can read your active listings, so treat it like a public API key. You can regenerate it at any time from the settings page.

The feed includes ads with status forsale, incoming, or sold. Draft and archived ads are always excluded. Sold ads are kept so you can show a "sold" badge — filter them out client-side (or via ?status= on the edge feed) if you only want live listings.

Your feed URLs look like this

Direct Feed
https://app.yachtmaster.cloud/feed/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Edge Feed
https://ads.yachtmaster.cloud/v1/ads/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Direct Feed

app.yachtmaster.cloud

Pull listings directly from the app server. Data is always current — fetched live from the database on every request.

GET /feed/:token

Query parameters

ParameterTypeDescription
filter
stringReturn only ads tagged with this page value. Matches against the web_pages array on each ad. Example: ?filter=main
since
ISO 8601Return only ads updated after this timestamp. Use for incremental syncs. Example: ?since=2025-01-01T00:00:00Z

JavaScript

// Fetch all active ads
const res = await fetch(
  'https://app.yachtmaster.cloud/feed/YOUR_TOKEN'
);
const { ads } = await res.json();

// Fetch only ads tagged for your main website
const res = await fetch(
  'https://app.yachtmaster.cloud/feed/YOUR_TOKEN?filter=main'
);

// Incremental — only ads changed since last fetch
const res = await fetch(
  'https://app.yachtmaster.cloud/feed/YOUR_TOKEN?since=2025-01-01T00:00:00Z'
);

Response — 200 OK

{
  "feed_generated_at": "2025-01-15T08:00:00.000Z",
  "ads": [
    {
      "id": 1234,
      "status": "forsale",
      "object_type_id": 1,
      "object_type": "motorboat",
      "updated_at": "2025-01-14T12:00:00.000Z",
      "year": 2019,
      "make_name": "Beneteau",
      "model": "Oceanis 40.1",
      "price": 95000,
      "currency": "EUR",
      "vat": false,
      "vat_marginal": true,
      "length": 11.98,
      "width": 3.99,
      "draft": 2.05,
      "weight": 7800,
      "cabins": 3,
      "berths": 6,
      "toilets": 2,
      "engine_qty": 1,
      "engine_make_name": "Yanmar",
      "engine_model": "4JH45",
      "engine_year": 2019,
      "engine_type_name": { "en": "Inboard", "fi": "Sisäperämoottori", "sv": "Inombordare" },
      "engine_fuel_name": { "en": "Diesel", "fi": "Diesel", "sv": "Diesel" },
      "distance": 2340,
      "material_name": { "en": "GRP", "fi": "Lasikuitu", "sv": "GRP" },
      "country_code": "SE",
      "country_name": { "en": "Sweden", "fi": "Ruotsi", "sv": "Sverige" },
      "city_name": { "en": "Gothenburg", "fi": "Göteborg", "sv": "Göteborg" },
      "description": { "en": "...", "fi": "...", "sv": "..." },
      "subtitle": { "en": "...", "fi": "...", "sv": "..." },
      "web_url": "https://example.com/boats/1234",
      "web_pages": ["main"],
      "images": [
        {
          "id": "abc123def456",
          "name": "Main photo",
          "width": 1920,
          "height": 1080,
          "type": "jpg",
          "url": "https://cdn.yachtmaster.cloud/abc123def456",
          "category": "exterior"
        }
      ],
      "equipment": [
        {
          "equipment_group_name": { "en": "Navigation", "fi": "Navigointi", "sv": "Navigation" },
          "group_sort": 1,
          "equipment_items": [
            {
              "name": { "en": "GPS", "fi": "GPS", "sv": "GPS" },
              "description": "Garmin 742xs"
            }
          ]
        }
      ]
    },
    {
      "id": 1235,
      "status": "forsale",
      "object_type_id": 4,
      "object_type": "car",
      "updated_at": "2025-01-14T12:00:00.000Z",
      "year": 2021,
      "make_name": "Volvo",
      "model": "XC60",
      "price": 42000,
      "currency": "SEK",
      "vat": true,
      "vat_marginal": false,
      "body_type": "suv",
      "transmission": "automatic",
      "fuel_type": "diesel",
      "drive_type": "awd",
      "power_kw": 173,
      "engine_displacement": 1969,
      "color": "grey",
      "number_of_seats": 5,
      "number_of_doors": 5,
      "first_registration_date": "2021-03-01",
      "distance": 48000,
      "country_code": "SE",
      "country_name": { "en": "Sweden", "fi": "Ruotsi", "sv": "Sverige" },
      "city_name": { "en": "Gothenburg", "fi": "Göteborg", "sv": "Göteborg" },
      "description": { "en": "...", "fi": "...", "sv": "..." },
      "subtitle": { "en": "...", "fi": "...", "sv": "..." },
      "web_url": "https://example.com/cars/1235",
      "web_pages": ["main"],
      "images": [],
      "equipment": []
    }
  ]
}
Edge Feed

ads.yachtmaster.cloud

Edge-cached listings served from the Cloudflare network. Syncs automatically when ads are published. CORS headers are included on all responses so you can call this from browser JavaScript without a proxy.

GET /v1/ads/:token

Query parameters

ParameterTypeDescription
filter
stringReturn only ads tagged with this page value. Example: ?filter=main
since
ISO 8601Return only ads updated after this timestamp. Example: ?since=2025-01-01T00:00:00Z
status
stringFilter by ad status. Accepts a single value or comma-separated list. Valid values: forsale, incoming, sold. Example: ?status=forsale,incoming

Response — 200 OK

{
  "last_synced_at": "2025-01-15T08:00:00.000Z",
  "ads": [ /* same ad objects as Direct Feed */ ]
}
GET /v1/ads/:token/:id

Returns a single ad by ID. Returns 404 if the ad doesn't exist or doesn't belong to this token. The response is the same ad object as in the list endpoint.

JavaScript

// Fetch from the edge (browser-friendly, CORS enabled)
const res = await fetch(
  'https://ads.yachtmaster.cloud/v1/ads/YOUR_TOKEN'
);
const { last_synced_at, ads } = await res.json();

// Filter by page
const res = await fetch(
  'https://ads.yachtmaster.cloud/v1/ads/YOUR_TOKEN?filter=main'
);

// Filter by status — single value
const res = await fetch(
  'https://ads.yachtmaster.cloud/v1/ads/YOUR_TOKEN?status=forsale'
);

// Filter by status — multiple values (comma-separated)
const res = await fetch(
  'https://ads.yachtmaster.cloud/v1/ads/YOUR_TOKEN?status=forsale,incoming'
);

// Single ad
const res = await fetch(
  'https://ads.yachtmaster.cloud/v1/ads/YOUR_TOKEN/1234'
);

Reference

Ad object fields

Every ad in the ads[] array has the following fields. Fields with no value are returned as null.

Object types

Each ad's object_type slug maps to a numeric object_type_id. Slugs are stable — prefer them over the numeric id.

idslugDescription
1motorboatMotorboat
2sailboatSailboat
3trailerTrailer
4carCar
5truckTruck
6campervanCampervan
7motorbikeMotorbike
8work_machineWork machine
9snowmobileSnowmobile
10jetskiJetski / watercraft
11equipmentEquipment
12generalGeneral
always Always present nullable May be null boats Boat types only — null for cars cars Cars only — null for boats
FieldTypePresentDescription
idnumberalwaysUnique ad identifier
statusstringalwaysOne of: forsale, incoming, sold
object_type_idnumberalwaysNumeric object type: 1 = motorboat, 2 = sailboat, 10 = jetski, 4 = car (see full enum above)
object_typestringalwaysStable slug: motorboat, sailboat, trailer, car, truck, campervan, motorbike, work_machine, snowmobile, jetski, equipment, general. Branch on this, not the numeric id
updated_atISO 8601alwaysLast modification timestamp
pricenumbernullableAsking price (null = price on request)
currencystringnullableISO 4217 currency code (e.g. EUR, SEK)
vatbooleannullablePrice includes VAT
vat_marginalbooleannullableMargin scheme VAT applies
yearnumbernullableBuild year
make_namestringnullableManufacturer name
modelstringnullableModel name
distancenumbernullableEngine hours (boats) or mileage in km (cars)
descriptionobjectnullableLocalised description: { en, fi, sv }
subtitleobjectnullableLocalised short description: { en, fi, sv }
country_codestringnullableISO 3166-1 alpha-2 country code
country_nameobjectnullableLocalised country name: { en, fi, sv }
city_nameobjectnullableLocalised city name: { en, fi, sv }
zip_codestringnullablePostal code
web_urlstringnullableURL to the listing on your own website
web_pagesstring[]alwaysPage tags this ad is published to (may be empty)
imagesobject[]alwaysArray of image objects (may be empty, see below)
equipmentobject[]alwaysArray of equipment groups (may be empty, see below)
lengthnumberboatsLength overall in metres
widthnumberboatsBeam in metres
draftnumberboatsDraft in metres
weightnumberboatsDisplacement in kg
cabinsnumberboatsNumber of cabins
berthsnumberboatsNumber of berths
toiletsnumberboatsNumber of toilets
material_nameobjectboatsLocalised hull material: { en, fi, sv }
engine_qtynumberboatsNumber of engines
engine_make_namestringboatsEngine manufacturer
engine_modelstringboatsEngine model
engine_yearnumberboatsEngine build year
engine_type_nameobjectboatsLocalised engine type: { en, fi, sv }
engine_fuel_nameobjectboatsLocalised fuel type: { en, fi, sv }
body_typestringcarsBody style slug (e.g. suv, sedan, station_wagon)
transmissionstringcarsmanual, automatic or sequential
fuel_typestringcarsgasoline, diesel, electric, hybrid, ethanol or gas
drive_typestringcarsfwd, rwd or awd
power_kwnumbercarsEngine power in kW
engine_displacementnumbercarsEngine displacement in cm³
colorstringcarsExterior colour slug (e.g. black, silver, blue)
number_of_seatsnumbercarsNumber of seats
number_of_doorsnumbercarsNumber of doors
first_registration_dateISO 8601 datecarsDate of first registration
Image object
idstringUnique image identifier
namestringImage label
widthnumberWidth in pixels
heightnumberHeight in pixels
typestringFormat: jpg, webp, png
urlstringFull CDN URL to the image file
categorystring | nullAI-classified image type: cruising, exterior, interior, layout, technical, or null if unclassified
Equipment group object
equipment_group_nameobjectLocalised group label: { en, fi, sv, ... }
group_sortnumberDisplay sort order
equipment_itemsobject[]Array of equipment item objects (see below)
Equipment item object
nameobjectLocalised equipment name: { en, fi, sv, de, fr, ... }
descriptionstring | nullOptional free-text note about this specific item on the boat

Webhook notifications

Instead of polling, you can configure a webhook endpoint in Settings → Adflow → Web pages. YachtMaster will send a POST to your endpoint whenever an ad is published or updated.

{ "event": "ads.updated", "updated_at": "..." }

On receiving this, fetch the feed to get updated listings. An optional API key can be added to the webhook for request validation.

Multiple page feeds

Each ad can be tagged to one or more page filters (e.g. main, regional). Use ?filter= to serve different feeds from the same token — one per website or section.

/feed/TOKEN?filter=main
/feed/TOKEN?filter=regional

Errors

Errors return the appropriate HTTP status with a JSON body of the shape { "error": "message" }. Successful responses return 200.

StatusWhen
200Success. Feed or single ad returned.
404Unknown or inactive feed token, or (single-ad endpoint) an ad id that does not exist for this token.
502Edge feed only — the upstream YachtMaster app could not be reached during a sync.

Caching & sync

Responses are cacheable for 60 seconds. The direct feed is token-gated and returns Cache-Control: private, max-age=60 (client cache only); the edge feed is CDN-cacheable and returns public, max-age=60. The feed is not paginated — all matching ads return in a single response.

For incremental syncing, pass ?since=<ISO 8601> to receive only ads modified after that time, or use the webhook to trigger a refetch.

Versioning & compatibility

New fields are added additively and are not considered breaking — your integration should ignore unknown fields rather than fail on them.

Any breaking change (a removed or renamed field, or changed semantics) ships under a new version path. The edge feed is versioned at /v1/.

Machine-readable spec

The full contract is published as an OpenAPI 3.1 document — import it into Postman, Insomnia, or a code generator.

OpenAPI spec

Get started

Ready to display your listings?

Enable Adflow in your YachtMaster settings and your feed is live in minutes.

enfisv