> ## Documentation Index
> Fetch the complete documentation index at: https://demo-travel.webbinghub.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Front end: screens call the server through one typed client

> Omnibeds screens call commands with api(name, input, doing). See how the typed client works, how errors come back, and how big pages are split.

Omnibeds screens never build a URL or call `fetch` for an action. They call `api()` from `lib/client/api.ts` with a command's name, and the compiler checks the input and the answer against that command.

## Call a command

```typescript theme={null}
import { api } from "@/lib/client/api";

const res = await api("cancel", { reference: booking.reference, mode }, t("doingCancel"));
if (!res.ok) return showProblem(res.problem, t("couldntCancel"));
setSelected(res.data.booking);
```

| Argument | What it is |
| - | - |
| `name` | The command's export name, such as `cancel` or `openQuote`. |
| `input` | The command's schema input. Fields with defaults may be left out. Route params such as `reference` are part of it. |
| `doing` | The action in words, used in the error message ("Cancelling the booking"). |

`api()` never throws. It returns `{ ok: true, data }` or `{ ok: false, problem }`, where `problem` is what the server explained: a `code`, a `message`, and any extra fields in `details` (for example the refreshed price check when an offer changed).

## How it finds the URL

`ROUTES` maps every command to its method and path, for example `cancel: POST /api/cancel` and `rebookBook: POST /api/bookings/:reference/rebook`. `api()` fills `:params` from the input, then sends the rest as a query string for GET and DELETE, or as a JSON body otherwise.

For a link the browser opens itself, such as a PDF download, `apiUrl(name, input)` returns the URL of a GET command.

> [!NOTE]
>
> Only types cross into the browser: `lib/client/api.ts` imports the command modules with `import type`, so no server code is bundled into a screen.

## Keep logic out of screens

A page places its parts and holds no business rules. When a page grows, its state and its calls move into a hook, and its sections into components:

| Page | Hook (state and calls) | Parts |
| - | - | - |
| Book an offer | `components/book/use-booking-flow.ts` | `components/book/steps.tsx`, `parts.tsx` |
| A quote | `components/quotes/detail/use-quote-detail.ts` | header actions, banners, options, client panel |

Rules that aren't about display live in `lib/`, where they can be tested without a browser: search filtering and merging in `lib/search/`, and the traveller helpers (a party from saved travellers, age checks on arrival) in `lib/travellers/`.

## Calls that stay outside api()

A few calls aren't commands and keep their own fetch: the search stream and its sentence parser, presenter unlock, the user switcher (session), the quota counter, the access gate, the guided tour and the client's accept link on a shared quote.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.