{"openapi":"3.1.0","info":{"title":"Boatfront API","version":"1.0.0","summary":"Read and manage used-yacht classified listings on Boatfront.","description":"Boatfront is a worldwide marketplace for buying and selling used yachts.\nSellers are private individuals and brokers; buyers browse listings, save\nthem, and contact the seller through an enquiry.\n\n**Status: pre-launch.** The marketplace is not open yet. The endpoints below are live but the public collections are empty until launch.\n\nAuthentication is optional for the public read endpoints and required for\neverything that touches a specific account. Register an OAuth 2.1\napplication or mint an API key in the developer portal.\n\nTerms: https://boatfront.com/en/terms · Privacy: https://boatfront.com/en/privacy","contact":{"name":"Boatfront","email":"hello@boatfront.com","url":"https://boatfront.com"},"termsOfService":"https://boatfront.com/en/terms","license":{"name":"Proprietary","url":"https://boatfront.com/en/terms"}},"servers":[{"url":"https://boatfront.com","description":"Production"}],"externalDocs":{"description":"Agent guidance","url":"https://boatfront.com/llms.txt"},"tags":[{"name":"Listings","description":"Boat advertisements."},{"name":"Enquiries","description":"Buyer-to-seller contact."},{"name":"Reference","description":"Catalogue data used to build listings and filters."},{"name":"Account","description":"The authenticated user's own data."}],"paths":{"/api/listings":{"get":{"tags":["Listings"],"summary":"List active listings","description":"Paginated collection of active, non-deleted listings. Public — no credentials required. Pass `mine=true` with a credential to list the caller's own listings instead, including drafts.","operationId":"listListings","security":[{},{"oauth2":["listings:read"]},{"apiKey":[]}],"parameters":[{"name":"page","in":"query","description":"1-based page number.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","description":"Page size. Values above 100 are clamped to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"mine","in":"query","description":"Return the authenticated caller's own listings. Requires a credential.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"A page of listings.","content":{"application/json":{"schema":{"type":"object","required":["data","total","page","limit","hasMore"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}},"401":{"description":"`mine=true` without a valid credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Credential lacks the `listings:read` scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Retry after the interval in `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Listings"],"summary":"Create a listing","description":"Creates a listing as a draft. Publishing is a paid action: set `status` to `pending` and follow `checkoutUrl` to Stripe Checkout. Requires a signed-in session — not available to API keys.","operationId":"createListing","security":[{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","category","price"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string","enum":["sail","motor","other"]},"price":{"type":"number"},"currency":{"type":"string","default":"GBP"},"specs":{"type":"object"},"location":{"type":"object"},"images":{"type":"array","items":{"type":"object"}},"featureSlugs":{"type":"array","items":{"type":"string"}},"sellerBrokerId":{"type":"string","description":"Only accepted when the caller is a member of that broker, or an admin."},"status":{"type":"string","enum":["draft","pending"],"default":"draft"}}}}}},"responses":{"200":{"description":"The created listing, plus a Stripe Checkout URL when publishing.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Listing"},"checkoutUrl":{"type":"string","format":"uri"}}}}}},"401":{"description":"No session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not a member of the requested broker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/listings/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"get":{"tags":["Listings"],"summary":"Get a listing","description":"Active listings are public. A listing in any other state is visible only to its owner, that owner's broker, or an admin — everyone else gets 404 rather than 403, so the response never confirms the id exists.","operationId":"getListing","security":[{},{"oauth2":["listings:read"]},{"apiKey":[]}],"responses":{"200":{"description":"The listing.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Listing"}}}}}},"404":{"description":"No such listing, or it is not visible to the caller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/listings/suggestions":{"get":{"tags":["Reference"],"summary":"Autocomplete values from active listings","description":"Distinct makes, or models for a given make. Cached for an hour.","operationId":"listListingSuggestions","parameters":[{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["make","model"]}},{"name":"make","in":"query","description":"Required when `type=model`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Distinct values, alphabetically.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}}}}}}}}},"/api/features":{"get":{"tags":["Reference"],"summary":"Feature catalogue","description":"The active equipment/feature catalogue. `slug` values here are the only ones accepted in a listing's `featureSlugs`.","operationId":"listFeatures","responses":{"200":{"description":"The catalogue.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"label":{"type":"string"},"category":{"type":"string"}}}}}}}}}}}},"/api/enquiries":{"post":{"tags":["Enquiries"],"summary":"Send an enquiry to a seller","description":"Emails the seller of a listing. Anonymous but bot-checked and rate limited: one enquiry per IP per listing per 60 seconds, and ten per IP per hour. This is the marketplace's primary conversion — do not call it speculatively on a buyer's behalf without their intent.","operationId":"createEnquiry","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["listingId","name","email","message"],"properties":{"listingId":{"type":"string","maxLength":64},"name":{"type":"string","minLength":2,"maxLength":120},"email":{"type":"string","format":"email","maxLength":254},"phone":{"type":"string","maxLength":40},"message":{"type":"string","minLength":10,"maxLength":5000}}}}}},"responses":{"200":{"description":"The enquiry was accepted and emailed to the seller.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Rejected as automated traffic.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/saved":{"get":{"tags":["Account"],"summary":"List the authenticated user's saved listings","description":"Saved listings that are still active or sold. Session-authenticated.","operationId":"listSavedListings","security":[{"session":[]}],"responses":{"200":{"description":"Saved listings.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}}}}}}},"401":{"description":"No session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Account"],"summary":"Save or unsave a listing","operationId":"toggleSavedListing","security":[{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["listingId"],"properties":{"listingId":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["save","unsave"],"default":"save","description":"Anything other than `unsave` saves the listing."}}}}}},"responses":{"200":{"description":"The listing was saved or unsaved."},"400":{"description":"`listingId` missing or not a string.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No session, or the session no longer maps to a user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"Listing":{"type":"object","description":"A classified advertisement for a used yacht or boat.","required":["id","slug","title","category","specs","price","currency","location","status"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"URL segment used by /{locale}/boats/{slug}."},"title":{"type":"string"},"description":{"type":"string"},"category":{"type":"string","enum":["sail","motor","other"]},"specs":{"type":"object","properties":{"make":{"type":"string"},"model":{"type":"string"},"year":{"type":"integer"},"lengthM":{"type":"number","description":"Length overall, metres."},"beamM":{"type":"number"},"draftM":{"type":"number"},"hullType":{"type":"string"},"rigging":{"type":"string"},"boatClass":{"type":"string"},"engineMake":{"type":"string"},"engineModel":{"type":"string"},"engineHours":{"type":"integer"},"fuelType":{"type":"string"},"hullMaterial":{"type":"string"},"cabins":{"type":"integer"},"berths":{"type":"integer"}}},"price":{"type":"number"},"currency":{"type":"string","description":"ISO 4217 code, e.g. GBP."},"negotiable":{"type":"boolean"},"bespoke":{"type":"boolean"},"yachtName":{"type":"string"},"images":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"isPrimary":{"type":"boolean"},"kind":{"type":"string","enum":["image","video"]}}}},"location":{"type":"object","properties":{"city":{"type":"string"},"countryCode":{"type":"string","description":"ISO 3166-1 alpha-2."},"lat":{"type":"number"},"lng":{"type":"number"}}},"seller":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["private","broker"]},"brokerSlug":{"type":"string"}}},"featureSlugs":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["draft","pending","active","expired","sold"]},"views":{"type":"integer"},"saves":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error","code","message","status"],"properties":{"error":{"type":"string","description":"Human-readable summary. Same text as `message`."},"code":{"type":"string","description":"Stable machine-readable error code. Branch on this, not on the message.","enum":["bad_request","unauthorized","forbidden","insufficient_scope","not_found","method_not_allowed","rate_limited","internal_error"]},"message":{"type":"string"},"status":{"type":"integer"},"hint":{"type":"string","description":"What the caller should do about it."},"documentation":{"type":"string","format":"uri"}}}},"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.1 authorisation code flow with PKCE. Register an application in the developer portal to obtain a client id.","flows":{"authorizationCode":{"authorizationUrl":"https://boatfront.com/api/auth/oauth2/authorize","tokenUrl":"https://boatfront.com/api/auth/oauth2/token","refreshUrl":"https://boatfront.com/api/auth/oauth2/token","scopes":{"listings:read":"View and search boat listings","listings:write":"Create and manage boat listings","broker:read":"View broker profiles and analytics","broker:write":"Manage broker profiles and team"}}}},"apiKey":{"type":"http","scheme":"bearer","description":"An API key minted in the developer portal, sent as `Authorization: Bearer <key>`. Keys default to the `listings:read` scope."},"session":{"type":"apiKey","in":"cookie","name":"better-auth.session_token","description":"Browser session cookie. Not available to server-to-server callers."}}}}