# Booking on your own website

> Put Booking Orbit on your website with the widget, or build your own booking screens with the JavaScript SDK and the public booking API.

Source: https://docs.bifrostorbit.com/booking/developers/booking-sdk/

There are three ways to take bookings on your own website, from least to most work:

1. **A link** to the hosted booking page.
2. **The widget**, which shows the booking page inside your page or in a popup.
3. **The SDK** or the **public booking API**, to build screens in your own design.

## The widget

Add the script once, then a placeholder where the booking page should appear:

```html
<script src="https://app.bifrostorbit.com/booking/widget.js" async></script>
<div data-booking-orbit="northwilds-oslo" data-service="boot-fitting"></div>
```

Or open it in a popup from any button or link:

```html
<button type="button" data-booking-orbit-open="northwilds-oslo" data-service="boot-fitting">Book a fitting</button>
```

Optional attributes: `data-service` (start with one service), `data-staff` (a person's id), `data-lang` (`en`, `nb`, `de`). The frame grows with its content, so there is no inner scroll bar. From your own code, `window.BookingOrbit.open({ location: 'northwilds-oslo', service: 'boot-fitting' })` opens the popup.

**Booking page** in Booking Orbit has the code ready to copy.

## The SDK

```sh
npm install @bifrost-orbit-booking/sdk
```

```ts
import { createBookingClient } from "@bifrost-orbit-booking/sdk";

const booking = createBookingClient({ baseUrl: "https://app.bifrostorbit.com/booking", location: "northwilds-oslo", locale: "en" });

const services = await booking.services();
const slots = await booking.slots({ service: services[0]!.id, timeZone: "Europe/Oslo", days: 7 });
const time = slots.days.flatMap((day) => day.slots)[0]!;
const hold = await booking.hold({ service: services[0]!.id, startsAt: time.startsAt });
const { appointment } = await booking.book({ service: services[0]!.id, startsAt: time.startsAt, holdToken: hold.token, name: "Ingrid Berg", email: "ingrid@northwilds.com" });
```

The client has `location()`, `services()`, `service()`, `staff()`, `slots()`, `nextAvailable()`, `hold()`, `release()`, `book()`, `appointment()`, `reschedule()`, `cancel()`, `calendarUrl()` and `joinWaitlist()`. A taken time throws `BookingConflictError`; `isTimeTaken(error)` checks for it.

To book from the browser on your own website, add the website under **Settings**, allowed websites. Reading services and free times works from any website. A website space connected in CMS Orbit adds its own addresses.

To move an appointment, pass its manage token to `slots({ service, manage })`, so the appointment's own time counts as free, then call `reschedule()`.

## The public booking API

Everything the SDK does is plain JSON over HTTPS at `https://app.bifrostorbit.com/booking/api/public/<location>`:

| Method | Path | What it does |
| --- | --- | --- |
| GET | `/` | The location: name, address, time zone, languages, opening hours, what the booking page asks |
| GET | `/services` | Listed services |
| GET | `/services/<id or address>` | One service, with its people and form questions |
| GET | `/staff?service=` | People who can be booked |
| GET | `/slots?service=&staff=&from=&days=&timeZone=&manage=` | Free times, grouped by day in the time zone you ask for (up to 42 days), and the next free time |
| POST | `/holds` | Hold a time for 10 minutes: `{ service, staff, startsAt }` |
| DELETE | `/holds/<token>` | Let a held time go |
| POST | `/appointments` | Book: `{ service, staff, startsAt, holdToken, name, email, phone, notes, answers, marketing, locale, timeZone }` |
| GET | `/manage/<token>` | An appointment by its manage token |
| POST | `/manage/<token>/reschedule` | Move it: `{ startsAt, staff }` |
| POST | `/manage/<token>/cancel` | Cancel it: `{ reason }` |
| GET | `/manage/<token>/calendar` | The appointment as a calendar file |
| POST | `/waitlist` | Join the waitlist: `{ service, staff, from, to, name, email }` |

Answers come as `{ "data": … }`, errors as `{ "error": { "code", "message" } }`. Times are ISO 8601 in UTC. Holding, booking and changing are limited per visitor, and answer `429` when there are too many tries.
