# nisebookings

A hosted booking service for businesses: appointments, group bookings, recurring series, packages, waiting
lists and event tickets. It ships three surfaces:

| Surface | What it is | For |
|---|---|---|
| **Embeddable widget** | two dependency-free web components you paste into any site | any website, WordPress |
| **Public REST API** | the same engine without UI, one public key per business | custom front-ends, apps, agents |
| **Admin back office** | calendar, appointments, catalogue, payments, mail templates | the business |

The engine is strict where it matters: slots are re-checked and written transactionally, capacity can
never be exceeded, prices are always recomputed server-side, and all time is anchored to the business's
time zone.

## Start here

| Your task | Read |
|---|---|
| Decide whether this fits (and when not to use it) | [When to use it](09-when-to-use.md) |
| Test against a throwaway sandbox, no sign-up | [Sandbox](08-sandbox.md) |
| Put bookings on a website in 5 minutes | [Quickstart](01-quickstart.md) |
| Understand services, slots, capacity, money, time | [Concepts](02-concepts.md) |
| Configure the widget (attributes, flows, styling) | [Widget reference](03-widget-reference.md) |
| Build a custom front-end on the API | [Public API](04-public-api.md) · [openapi.yaml](openapi.yaml) · [verified examples](examples/README.md) |
| Integrate into a Next.js app | [Next.js](11-nextjs.md) · [runnable example](examples/nextjs/README.md) |
| Configure your account from code (no admin UI) | [Management API](../api/README.md) · [openapi.yaml](../api/openapi.yaml) |
| Let Claude Code, Codex, Cursor or VS Code operate your account | [MCP server](../api/mcp.md) |
| Get notified of bookings, cancellations, tickets and payments | [Webhooks](10-webhooks.md) |
| Use the back office | [Admin guide](05-admin-guide.md) |
| Change e-mail templates | [Notifications](06-notifications.md) |
| Know what data is stored and who can see it | [Data and privacy](07-data-and-privacy.md) |
| Feed a coding agent | [Agent instruction files](agents/README.md) |

## 5-minute integration

```html
<script src="https://app.nisebookings.com/widget.js" defer></script>
<nise-booking data-key="<your public key>"></nise-booking>
```

The customer gets service → time → details → payment → confirmation, in a shadow-DOM element that
inherits your page's font and is themed with CSS custom properties. Event tickets:
`<nise-events data-key="…">`. WordPress: paste the same two lines into a **Custom HTML** block.

## Headless integration

```js
const API = 'https://app.nisebookings.com/api/public/<your public key>';

const { tenant, services } = await (await fetch(`${API}/services`)).json();
const { days } = await (await fetch(`${API}/slots?service=${id}&from=2026-10-14&days=7`)).json();
const res = await fetch(`${API}/bookings`, {
  method: 'POST', headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    items: [{ service: id, staff: days[0].slots[0].staffId, start: days[0].slots[0].start, persons: 1 }],
    name: 'Ada Jansen', email: 'ada@example.com', gateway: 'local',
  }),
});
```

Send back the exact `start` you were given; handle `409 slot_unavailable` by re-fetching slots. Add an
`Idempotency-Key` header so a retry after a timeout never books twice.

## The five things to know

1. **Account = public key.** One key identifies the business on every public call. Nothing else is
   needed to embed or book.
2. **One order = one payment.** A cart, a chain, a repeated series or the parts of a compound service
   are all one checkout, with one payment and one order token.
3. **The client never decides.** Prices, staff, extras, capacity and slot availability are recomputed
   server-side inside a transaction with per-staff locks. The only thing the client must get right is
   sending back the `start` (and `staffId`) it received.
4. **Time is UTC on the wire, business-local in the UI.** Slot `start` values are ISO UTC; `from`/`until`
   are business-local dates; schedules, holidays and reminders use the business time zone.
5. **Timed work runs on its own.** Reminders, mail delivery, payment expiry, waiting-list offers and
   automatic status changes are processed by the service about once a minute; there is nothing to
   schedule on your side.

## For AI agents and coding agents

- [`agents/`](agents/README.md) — drop-in instruction files: `AGENTS.md` (Codex, Cursor, Copilot
  coding agent, VS Code, …), a Claude Code skill, and a Copilot instructions file. Copy one into the
  project that integrates this service.
- [`08-sandbox.md`](08-sandbox.md) — `POST /api/sandbox` returns a 24-hour test account with a public
  key and an all-scopes API key; no mail is delivered (read it via `GET /api/v1/outbox`), payments
  are fake. Verify your integration there before touching your real account.
- [`10-webhooks.md`](10-webhooks.md) — signed event messages (Standard Webhooks) to your backend for
  bookings, tickets and payments, with retries and a deliveries log; a dependency-free verifier.
- [`examples/`](examples/README.md) — three smallest-possible integrations; all run against a sandbox
  key, including a full Next.js app (widget and own UI) with every page explained in
  [`11-nextjs.md`](11-nextjs.md).
- [`llms.txt`](llms.txt) — this documentation as an index, per the llmstxt.org convention.
- [`llms-full.txt`](llms-full.txt) — every guide page concatenated into one file.
- [`openapi.yaml`](openapi.yaml) · [`openapi.json`](openapi.json) — machine-readable description of
  the whole public API (OpenAPI 3.1), in YAML and JSON.

When implementing a booking feature: start at [Quickstart](01-quickstart.md), fall back to the
[Public API](04-public-api.md) for anything the widget does not expose, and treat
[Concepts](02-concepts.md) as the source of truth for slot, capacity and pricing semantics. The
[Data and privacy](07-data-and-privacy.md) page explains what is stored, how accounts are isolated
and what is reachable from outside.

## What this service is not (yet)

- The [management API](../api/README.md) and the [MCP server](../api/mcp.md) cover what the admin does
  except creating real accounts (a 24-hour [sandbox](08-sandbox.md) can be created with one call) and
  the dashboard statistics. The MCP server takes API keys only (no OAuth yet).
- No customer accounts or "my bookings" area; bookings are managed through magic links: cancel a
  single booking (`/b/<token>`) or a whole order (`/o/<token>`), reschedule a single booking on
  `/b/<token>` or with `POST bookings/{token}/reschedule`.
- No SMS/WhatsApp and no external calendar sync.
- Admin UI is Dutch-only; the widget's text is Dutch **and English** (`data-lang`, or the account's language in Instellingen → Algemeen).
- No plans, quotas or billing layer — accounts are isolation + roles.

[`09-when-to-use.md`](09-when-to-use.md) turns this into a decision table with alternatives.
