Getting started
The platform is headless: a JSON API plus an embeddable booking widget that drops into any site — plain HTML, React, Next.js, Astro, or anything else that can load a script tag. There’s no iframe and no redirect; the widget renders inside a Shadow DOM on your page and talks to the API directly.
The two-tag embed
The fastest integration is the auto-mount. Add a mount element and the widget script:
<div
data-booking-widget
data-api-base="https://api.example.com"
data-publishable-key="pk_YOUR_KEY"
></div>
<script src="https://api.example.com/widget.global.js"></script>
That’s the whole integration. On load, the script finds every [data-booking-widget]
element and mounts the full booking flow — trip selection, live availability with
weather/tide, add-ons, waiver, payment, confirmation.
Mount attributes
| Attribute | Required | What it does |
|---|---|---|
data-booking-widget | yes | Marks the element for auto-mount. |
data-publishable-key | yes | Your pk_… key — scopes everything to your operator account. The widget does not mount without it. |
data-api-base | no | API origin. Omit (or set "") when the page is served from the same origin as the API — the widget then uses relative URLs. |
data-trip-type-id | no | Skip trip selection and open directly on one trip type. |
Serve the embed from a page you trust. The widget reads
data-api-baseoff its host element and sends the publishable key and the customer’s contact details to that origin. The publishable key is a public credential by design, but the host page is part of your security boundary — don’t embed on pages where third-party scripts could rewrite the attribute.
The mount() API
Framework hosts usually skip the data-attributes and call mount() on a node they own.
It returns an unmount function:
const unmount = window.BookingWidget.mount(element, {
apiBase: "https://api.example.com", // "" for same-origin
publishableKey: "pk_YOUR_KEY",
tripTypeId: "tt_…", // optional
});
Per-framework guides, each lifted verbatim from a working example app in the repo:
- Plain HTML — the two-tag auto-mount.
- React (Vite) —
mount()from auseEffect. - Next.js —
mount()from a client component. - Astro — auto-mount from a static page.
Make it yours
The widget is deliberately neutral out of the box — it inherits your page’s look until you theme it. One CSS custom property makes it match your brand; the full contract is small and documented in the theming guide.
Behind the widget: the API
Everything the widget does is public API you can call yourself — availability, holds, bookings, promo codes, gift cards, waitlists, weather. The same surface powers the operator admin and the customer portal. See the API reference for every route, auth tier, and shape.
| Tier | Credential | For |
|---|---|---|
| Publishable key | X-Publishable-Key: pk_… header | Widget-side reads + checkout writes. Safe to ship in a page. |
| Operator session | POST /v1/operator/login → cookie or Bearer | Your back office: schedule, bookings, money, CRM. |
| Customer session | Magic-link exchange → cookie or Bearer | The angler’s self-service portal. |
Money is always integer cents. Errors are uniform:
{ "error": { "code": "…", "message": "…" } }.