Marina API

Embed live berth availability and a full booking flow directly on your marina's own website — powered by Sidon.

Your API Key and Marina ID are in the Sidon dashboard under Overview → Website Embed & API.

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:

MethodPathAuthPurpose
GET/api/marina/public/{marinaId}OpenMarina profile, berths, POIs, announcements
GET/api/marina/public/{marinaId}/availabilityOpenWhich berths are booked for a date range
POST/api/marina/public/{marinaId}/create-intentAPI KeyCreate a Stripe payment intent (optional)
POST/api/marina/public/{marinaId}/bookAPI KeyCreate a booking (pending or confirmed)
DELETE/api/marina/public/{marinaId}/book?bookingId=NAPI KeyCancel 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.

StatusMeaning
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

ParameterTypeRequiredDescription
arrivalstringYesArrival date YYYY-MM-DD
departurestringYesDeparture 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

FieldTypeRequiredDescription
berthIdstringYese.g. "A2"
arrivalDatestringYesYYYY-MM-DD
departureDatestringYesYYYY-MM-DD
nightsnumberYesNumber of nights (≥ 1)
boatLoanumberYesBoat 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

FieldTypeRequiredDescription
berthIdstringYes
arrivalDatestringYesYYYY-MM-DD
departureDatestringYesYYYY-MM-DD
sailorNamestringYesGuest's full name
sailorEmailstringYesGuest's email
boatNamestringYes
statusstringNo"pending" (default) or "confirmed". Pass "confirmed" if you have already taken payment yourself.
boatLoanumberNoLength overall (m)
boatBeamnumberNoBeam (m)
paymentIntentIdstringNoFrom create-intent response
amountCentsnumberNoFrom create-intent response
notesstringNoGuest 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

ParameterTypeRequiredDescription
bookingIdnumberYesThe 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