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
- Always returns the full current set of ads
- No setup required beyond your 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
- Mirrors the app with up to 15 minutes of delay
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
https://app.yachtmaster.cloud/feed/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxhttps://ads.yachtmaster.cloud/v1/ads/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxapp.yachtmaster.cloud
Pull listings directly from the app server. Data is always current — fetched live from the database on every request.
/feed/:tokenQuery parameters
| Parameter | Type | Description |
|---|---|---|
filter | string | Return only ads tagged with this page value. Matches against the web_pages array on each ad. Example: ?filter=main |
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'
);
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" },
"summary": { "en": "...", "fi": "...", "sv": "..." },
"description": { "en": "...", "fi": "...", "sv": "..." },
"subtitle": { "en": "...", "fi": "...", "sv": "..." },
"web_url": "https://example.com/boats/1234",
"web_pages": ["main"],
"images": [
{
"id": "2f1c9a4e-8d3b-4c6e-9a1f-5b7d2e8c4a10",
"name": "Main photo",
"width": 1920,
"height": 1080,
"type": "image/jpeg",
"url": "https://media.yachtmaster.cloud/12/object-image/2f1c9a4e-8d3b-4c6e-9a1f-5b7d2e8c4a10.jpg",
"variants": {
"320": "https://media.yachtmaster.cloud/12/object-image/2f1c9a4e-8d3b-4c6e-9a1f-5b7d2e8c4a10@320.webp",
"1280": "https://media.yachtmaster.cloud/12/object-image/2f1c9a4e-8d3b-4c6e-9a1f-5b7d2e8c4a10@1280.webp"
},
"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" },
"summary": { "en": "...", "fi": "...", "sv": "..." },
"description": { "en": "...", "fi": "...", "sv": "..." },
"subtitle": { "en": "...", "fi": "...", "sv": "..." },
"web_url": "https://example.com/cars/1235",
"web_pages": ["main"],
"images": [],
"equipment": []
}
]
}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.
/v1/ads/:tokenQuery parameters
| Parameter | Type | Description |
|---|---|---|
filter | string | Return only ads tagged with this page value. Example: ?filter=main |
status | string | Filter 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 */ ]
}/v1/ads/:token/:idReturns 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.
| id | slug | Description |
|---|---|---|
| 1 | motorboat | Motorboat |
| 2 | sailboat | Sailboat |
| 3 | trailer | Trailer |
| 4 | car | Car |
| 5 | truck | Truck |
| 6 | campervan | Campervan |
| 7 | motorbike | Motorbike |
| 8 | work_machine | Work machine |
| 9 | snowmobile | Snowmobile |
| 10 | jetski | Jetski / watercraft |
| 11 | equipment | Equipment |
| 12 | general | General |
always Always present nullable May be null boats Boat types only — null for cars cars Cars only — null for boats| Field | Type | Present | Description |
|---|---|---|---|
id | number | always | Unique ad identifier |
status | string | always | One of: forsale, incoming, sold |
object_type_id | number | always | Numeric object type: 1 = motorboat, 2 = sailboat, 10 = jetski, 4 = car (see full enum above) |
object_type | string | always | Stable slug: motorboat, sailboat, trailer, car, truck, campervan, motorbike, work_machine, snowmobile, jetski, equipment, general. Branch on this, not the numeric id |
updated_at | ISO 8601 | always | Last modification timestamp |
price | number | nullable | Asking price (null = price on request) |
currency | string | nullable | ISO 4217 currency code (e.g. EUR, SEK) |
vat | boolean | nullable | Price includes VAT |
vat_marginal | boolean | nullable | Margin scheme VAT applies |
year | number | nullable | Build year |
make_name | string | nullable | Manufacturer name |
model | string | nullable | Model name |
distance | number | nullable | Engine hours (boats) or mileage in km (cars) |
summary | object | nullable | Localised one-line sales pitch, at most 200 characters: { en, fi, sv } |
description | object | nullable | Localised description: { en, fi, sv } |
subtitle | object | nullable | Localised short description: { en, fi, sv } |
country_code | string | nullable | ISO 3166-1 alpha-2 country code |
country_name | object | nullable | Localised country name: { en, fi, sv } |
city_name | object | nullable | Localised city name: { en, fi, sv } |
zip_code | string | nullable | Postal code |
web_url | string | nullable | URL to the listing on your own website |
web_pages | string[] | always | Page tags this ad is published to (may be empty) |
images | object[] | always | Array of image objects (may be empty, see below) |
equipment | object[] | always | Array of equipment groups (may be empty, see below) |
length | number | boats | Length overall in metres |
width | number | boats | Beam in metres |
draft | number | boats | Draft in metres |
weight | number | boats | Displacement in kg |
cabins | number | boats | Number of cabins |
berths | number | boats | Number of berths |
toilets | number | boats | Number of toilets |
material_name | object | boats | Localised hull material: { en, fi, sv } |
engine_qty | number | boats | Number of engines |
engine_make_name | string | boats | Engine manufacturer |
engine_model | string | boats | Engine model |
engine_year | number | boats | Engine build year |
engine_type_name | object | boats | Localised engine type: { en, fi, sv } |
engine_fuel_name | object | boats | Localised fuel type: { en, fi, sv } |
body_type | string | cars | Body style slug (e.g. suv, sedan, station_wagon) |
transmission | string | cars | manual, automatic or sequential |
fuel_type | string | cars | gasoline, diesel, electric, hybrid, ethanol or gas |
drive_type | string | cars | fwd, rwd or awd |
power_kw | number | nullable | Engine power in kW — on boats and jet skis this is per engine |
engine_displacement | number | cars | Engine displacement in cm³ |
color | string | cars | Exterior colour slug (e.g. black, silver, blue) |
number_of_seats | number | cars | Number of seats |
number_of_doors | number | cars | Number of doors |
first_registration_date | ISO 8601 date | cars | Date of first registration |
id | string | Opaque, stable image identifier |
name | string | Image label |
width | number | Width in pixels |
height | number | Height in pixels |
type | string | MIME type, e.g. image/jpeg |
url | string | Full CDN URL to the image file (media.yachtmaster.cloud) |
variants | object | Fixed stored derivatives by name: 320, 640, 1280, 1920 (WebP), 640-avif, 1280-avif, 1920-avif (AVIF, same widths) and 1000 (JPEG), plus og (1200×630 JPEG for social cards). Serve inside a <picture> with the AVIF name first, then the webp of the same width, then url as the last resort. A name is absent when that derivative does not exist — fall back the same way. Sizes are fixed, do not construct your own resize URLs. |
category | string | null | AI-classified image type: cruising, exterior, interior, layout, technical, or null if unclassified |
equipment_group_name | object | Localised group label: { en, fi, sv, ... } |
group_sort | number | Display sort order |
equipment_items | object[] | Array of equipment item objects (see below) |
name | object | Localised equipment name: { en, fi, sv, de, fr, ... } |
description | string | null | Optional 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.
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.
Errors
Errors return the appropriate HTTP status with a JSON body of the shape { "error": "message" }. Successful
responses return 200.
| Status | When |
|---|---|
200 | Success. Feed or single ad returned. |
404 | Unknown or inactive feed token, or (single-ad endpoint) an ad id that does not exist for this token. |
502 | Edge 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.
There is no incremental mode: every call returns the full current set, so a sold or
unpublished ad simply drops out. Use the webhook to know when to refetch. The edge feed
mirrors the app and can lag it by up to 15 minutes; last_synced_at says when it last pulled.
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.
Get started
Ready to display your listings?
Enable Adflow in your YachtMaster settings and your feed is live in minutes.
