Marina API
Embed live berth availability and a full booking flow directly on your marina's own website — powered by Sidon.
Overview
The Sidon Marina API is a small REST API that gives your website read access to your marina's public data and write access to create bookings. All responses are JSON. All endpoints support CORS so they can be called directly from a browser.
There are four endpoints:
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/marina/public/{marinaId} | Open | Marina profile, berths, POIs, announcements |
| GET | /api/marina/public/{marinaId}/availability | Open | Which berths are booked for a date range |
| POST | /api/marina/public/{marinaId}/create-intent | API Key | Create a Stripe payment intent (optional) |
| POST | /api/marina/public/{marinaId}/book | API Key | Create a booking (pending or confirmed) |
| DELETE | /api/marina/public/{marinaId}/book?bookingId=N | API Key | Cancel a booking, freeing availability |
Authentication
The two write endpoints require your API Key in the X-Marina-Key request header. GET endpoints are public and require no key.
X-Marina-Key: mk_a1b2c3d4e5f6...
Keep your API Key secret. Do not expose it in client-side JavaScript. Call create-intent and book from your server or a serverless function. Base URL
All endpoints are relative to:
https://sidon.ai/api/marina/public/{marinaId} Replace {marinaId} with your Marina ID from the dashboard.
Errors
Errors return a non-2xx HTTP status with a plain-text or JSON body describing the problem.
Status Meaning 400Missing or invalid request fields 401Missing or invalid X-Marina-Key 404Marina not found 409Berth already booked or under maintenance 500Internal server error
GET Marina Data
GET /api/marina/public/{marinaId} Open Returns the full public record for a marina — profile, overlays, berths, POIs, and announcements. Also includes the Stripe publishable key for initialising Stripe.js on the client.
Response
{
"profile": {
"ownerId": "user_abc123",
"name": "Marina Turgutreis",
"lat": 37.0012,
"lng": 27.2756,
"description": "...",
"phone": "+90 252 382 0000",
"email": "info@marina-turgutreis.com",
"website": "https://marina-turgutreis.com",
"responseWindowHours": 24
},
"berths": [
{ "berthId": "A2", "pricePerNight": 6 },
{ "berthId": "B7", "pricePerNight": 8 }
],
"pois": [
{ "id": 1, "label": "Fuel Dock", "type": "fuel", "lat": 37.0015, "lng": 27.2760 }
],
"announcements": [
{ "id": 1, "title": "Summer hours", "body": "...", "pinned": 1 }
],
"fromPrice": 6,
"stripePublishableKey": "pk_live_..."
} GET Availability
GET /api/marina/public/{marinaId}/availability Open Returns the list of berth IDs that are already booked (pending or confirmed) for the given date range. A berth not in this list is available.
Query Parameters
Parameter Type Required Description arrivalstring Yes Arrival date YYYY-MM-DD departurestring Yes Departure date YYYY-MM-DD
Example
GET /api/marina/public/user_abc123/availability?arrival=2025-07-10&departure=2025-07-14
Response
{ "bookedBerths": ["A2", "C11"] } POST Create Intent
POST /api/marina/public/{marinaId}/create-intent API Key Creates a Stripe payment intent for a berth booking. The intent uses manual capture — the card is authorised but not charged until the marina confirms the booking.
Call this from your server. Never expose your API Key in browser code. Request Body
Field Type Required Description berthIdstring Yes e.g. "A2" arrivalDatestring Yes YYYY-MM-DD departureDatestring Yes YYYY-MM-DD nightsnumber Yes Number of nights (≥ 1) boatLoanumber Yes Boat length overall in metres
Response
// If the berth has a price set:
{
"requiresPayment": true,
"clientSecret": "pi_xxx_secret_yyy",
"paymentIntentId": "pi_xxx",
"amountCents": 14400
}
// If no price is set on the berth:
{ "requiresPayment": false } Pass clientSecret to Stripe.js on the client to mount a card element and confirm payment.
POST Book
POST /api/marina/public/{marinaId}/book API Key Creates the booking record. Call this after the Stripe payment intent has been confirmed on the client (or immediately if requiresPayment was false).
Request Body
Field Type Required Description berthIdstring Yes arrivalDatestring Yes YYYY-MM-DD departureDatestring Yes YYYY-MM-DD sailorNamestring Yes Guest's full name sailorEmailstring Yes Guest's email boatNamestring Yes statusstring No "pending" (default) or "confirmed". Pass "confirmed" if you have already taken payment yourself. boatLoanumber No Length overall (m) boatBeamnumber No Beam (m) paymentIntentIdstring No From create-intent response amountCentsnumber No From create-intent response notesstring No Guest notes
Response
{ "ok": true, "bookingId": 42, "status": "confirmed" } DELETE Cancel Booking
DELETE /api/marina/public/{marinaId}/book?bookingId=N API Key Cancels a booking, immediately freeing up that berth's availability for the dates. Use this when a sailor cancels through your own website.
Query Parameters
Parameter Type Required Description bookingIdnumber Yes The bookingId returned by POST /book
Response
{ "ok": true } Note: if the booking had a Sidon-managed payment intent, you will need to issue any refund directly in your Stripe dashboard.
Using Your Own Stripe Account
If you already take payments on your own website and just want Sidon to track availability, skip create-intent entirely. Take payment however you like, then call POST /book with "status": "confirmed" to block the dates immediately — no marina approval step needed.
Availability-only flow
// 1. Check availability (open, no key needed)
const { bookedBerths } = await fetch(
'https://sidon.ai/api/marina/public/YOUR_MARINA_ID/availability' +
'?arrival=2025-07-10&departure=2025-07-14'
).then(r => r.json());
// 2. Take payment with your own Stripe account (client-side)
const { error } = await stripe.confirmCardPayment(yourClientSecret, { ... });
// 3. On success — mark the berth as confirmed in Sidon (server-side)
await fetch('https://sidon.ai/api/marina/public/YOUR_MARINA_ID/book', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Marina-Key': process.env.MARINA_API_KEY,
},
body: JSON.stringify({
berthId: 'A2',
arrivalDate: '2025-07-10',
departureDate: '2025-07-14',
sailorName: 'James Morris',
sailorEmail: 'james@example.com',
boatName: 'Lazy Pelican',
status: 'confirmed', // ← skips approval, blocks dates immediately
}),
}).then(r => r.json());
// → { ok: true, bookingId: 42, status: "confirmed" }
// 4. When sailor cancels — free up the dates
await fetch(
'https://sidon.ai/api/marina/public/YOUR_MARINA_ID/book?bookingId=42',
{
method: 'DELETE',
headers: { 'X-Marina-Key': process.env.MARINA_API_KEY },
}
); The booking will appear in your Sidon dashboard as Confirmed and the berth availability will update immediately for that date range. Sidon Payments Embed
A complete booking flow from your website involves four steps:
1 — Fetch marina data
const res = await fetch('https://sidon.ai/api/marina/public/YOUR_MARINA_ID');
const { berths, stripePublishableKey } = await res.json(); 2 — Check availability
const avail = await fetch(
'https://sidon.ai/api/marina/public/YOUR_MARINA_ID/availability' +
'?arrival=2025-07-10&departure=2025-07-14'
);
const { bookedBerths } = await avail.json();
const available = berths.filter(b => !bookedBerths.includes(b.berthId)); 3 — Create payment intent (server-side)
// Your server / serverless function:
const intent = await fetch(
'https://sidon.ai/api/marina/public/YOUR_MARINA_ID/create-intent',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Marina-Key': process.env.MARINA_API_KEY,
},
body: JSON.stringify({
berthId: 'A2',
arrivalDate: '2025-07-10',
departureDate: '2025-07-14',
nights: 4,
boatLoa: 12,
}),
}
).then(r => r.json());
// Return intent.clientSecret to the browser 4 — Confirm payment and book (client-side)
// Browser:
const stripe = Stripe(stripePublishableKey);
const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: { card: cardElement },
});
if (!error) {
// Call your server to POST /book
await fetch('/your-server/book', { method: 'POST', ... });
} How Stripe Capture Works
Sidon uses manual capture PaymentIntents. This means:
- The guest's card is authorised (hold placed) but not charged at booking time.
- The marina reviews the booking in their Sidon dashboard and clicks Confirm — only then is the payment captured.
- If the marina declines or the booking expires, the authorisation is released automatically.
Stripe.js must be loaded from https://js.stripe.com/v3/. Initialise it with the stripePublishableKey returned from the GET endpoint.
Questions? Email support@sidon.ai