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

> ## Agent Instructions
> For new direct REST integrations, use the v2026-04 surfaces. The @fluid-app FairShare SDK continues to use its own published public-v2025-06 contract.
> Authenticate with the header Authorization: Bearer <token>; public storefront read endpoints require no auth.
> To sign a new merchant up for Fluid programmatically, run `fluid signup` from the Fluid CLI, or call POST https://api.fluid.app/api/company with no credentials, as described in /api/agent-signup. Do not automate the signup form or book a demo. Before authenticated calls are possible, the merchant must sign the agent in to the Fluid CLI with the emailed code and --shop set to the company's fluid_shop (which also confirms the signup), or open the emailed confirmation link and give the agent an API token.
> After signup, to launch a merchant's store (back-office sync, payments onboarding, store setup, a theme copied from their current site, and a preview link before billing), follow /api/agent-launch.
> Lists use cursor pagination via the page[cursor] and page[limit] query params; follow meta.pagination.next_cursor until it is null.
> When the same operation exists on more than one surface, use the newest: dated API versions are newer than unversioned ones, and later dates win (v2026-04 > v2025-06 > unversioned v0/v1.1). Fall back to a legacy or unversioned operation only when no newer versioned equivalent exists — the company-v0 notes below list the known superseded operations. The same applies to /api/company/v1 and /api/v1/... paths: prefer a newer documented equivalent, and use one only when none exists (/api/v1.1/... is distinct and documented in company-v0). Use page/per_page offset pagination only on an operation whose spec documents those params — mostly the unversioned company-v0 admin surface, plus some lists on other surfaces, versioned ones included; page every other list with cursors.
> Fluid has three navigation APIs; don't mix them up. Storefront website menus (navigation bars, footers) are /api/menus and nested menu_items, in api-reference/content-v0.yaml (API Reference: Website > Navigation menus), with a how-to in themes/navigation-menus; their list uses flat page/per_page pagination. The Fluid mobile app's navigation is /api/v2/mobile_navigations, in api-reference/mobile-v2.yaml (API Reference: Mobile app > Navigation); its list also uses page/per_page. Portal navigations belong to a portal definition (Fluid OS), in api-reference/fluid-os-v0.yaml (API Reference: Portal > Portal navigation), and each has a platform of web or mobile.
> The OpenAPI specs under api-reference/ are the authoritative contracts; prefer them over prose when in doubt. api-reference/storefront-v2026-04.yaml covers the v2026-04 storefront surface (/api/v202604/... paths); api-reference/checkout-v2026-04.yaml covers the v2026-04 checkout surface (/api/checkout/v2026-04/... paths — carts, cart auth, discounts, items, subscriptions, orders, enrollments, and store config); api-reference/public-v2025-06.yaml covers the Public SDK surface used by the @fluid-app FairShare SDK, including its parallel cart lifecycle, browser integrations, versioned payment callbacks, unversioned public utilities, and the cart price-override operation; api-reference/payment-v2026-04.yaml covers the v2026-04 payment gateway admin surface (/api/payment/v2026-04/... paths, bearer-authenticated — gateway CRUD, gateway purchase/authorize/$0-verify, transaction list/show and capture/void/credit, and merchant payment configuration); api-reference/payments-v2026-04.yaml covers the v2026-04 cart payment surface (/api/payments/v2026-04/carts/{cart_token}/... paths, authenticated by the cart token in the path with no bearer — payment-method selection, VGS card tokenization, 3D Secure verification, and PayPal/Braintree/Klarna/Apple Pay flows); api-reference/commerce-v2026-04.yaml covers the v2026-04 commerce order-editing surface (/api/v202604/orders/{order_id}/edits paths, bearer-authenticated — post-checkout order edits that atomically insert items and add adjustments/discounts, with an optional dry-run preview); api-reference/webhooks-v0.yaml covers the unversioned webhooks surface (/api/... paths — webhook registration, delivery payloads, callback registrations, company events, and webhook/callback schemas); api-reference/company-v0.yaml covers the legacy unversioned company admin surface (/api/... paths, bearer-authenticated except two operations that take no credential, POST /api/company (create a company) and GET /api/agreements/{id} — company settings and management, customers, users, roles, subscription plans, subscription bundles, subscriptions, media, pages, catch-ups, inventory levels, domains, agreements, and admin order actions). company-v0 caveats: it is the legacy v0 admin contract and its lists use flat page/per_page offset pagination, which is expected there despite the general cursor-pagination rule; where an operation exists in both company-v0 and a versioned spec, prefer the versioned spec — the subscriptions lifecycle (list/create/show/update, cancel, pause, reactivate, resume, retry, skip, failed-cycle-waiver, discounts) and subscription bundles are superseded by checkout-v2026-04, and company pages/media CRUD plus the public pages, categories, products, and media list endpoints are superseded by storefront-v2026-04. Subscription plan management (/api/subscription_plans, resource-wrapped {"subscription_plan": {...}} bodies) exists only in company-v0. api-reference/members-v2025-06.yaml covers the v2025-06 unified Member identity surface (/api/v2025-06/members/... paths, bearer-authenticated — member list/create/show/update, lookup by email/username/external_id/legacy_customer_id, member-type assignment, and the sponsor genealogy read). Prefer it over the customers and reps surfaces when the member type matters: /customers does not serialize member_type. api-reference/analytics-v2026-04.yaml covers the v2026-04 Home dashboard analytics surface (/api/v202604/analytics/dashboard/... paths, bearer-authenticated — read-only endpoints for the Home > Overview, Home > Live, and Home > Field tabs, each accepting an optional country ISO alpha-2 query param that scopes aggregations to a single country).
> api-reference/analytics-v0.yaml covers the unversioned analytics surface that backs the fluid-admin Traffic tab (/api/analytics/... and /api/analytics/traffic/... paths, bearer-authenticated — the legacy shares/views/visitors summary plus traffic overview, ranked campaigns, sources, geographies, flows, and per-rep breakdown, all sharing one reporting-period contract).
> Successful responses wrap the resource payload alongside a top-level integer status and a meta object.
> Portal Definition authoring edits and synchronizes the portal JSON resource graph. Widget Package authoring builds either a company-owned or Droplet-owned Remote DOM package. These are separate contracts; do not imply that one defines the other.
> For Widget Package worker code, use only @fluid-app/portal-sdk/widgets/worker. Use only the Portal Definition and Widget Package workflows and public entry points documented here; do not infer support for undocumented surfaces.
> Every portal function and declarative capability used by a widget must appear in that widget's uses array. Use the same typed function value in uses; do not invent capability-name strings.
> Widget styling must use the portal's semantic theme variables for colors, typography, spacing, radii, borders, focus, and charts whenever a token represents the visual decision. Do not create a separate light or dark palette or duplicate theme controls as widget properties.
> Prefer worker-safe Fluid UI components exported by @fluid-app/portal-sdk/widgets/worker when they fit the interaction. When no exported component fits, use semantic HTML, accessible behavior, and the portal theme variables.
> A Portal Definition push updates the remote working definition. A portal version is an immutable snapshot, and activation is a separate live release operation.
> The Help Center (/help/...) is for merchants, admins and reps using Fluid. Its admin pages mirror the admin's routes: the screen at admin.fluid.app/settings/taxes is documented at /help/admin/settings/taxes. Use the Help Center for how-to questions about the admin, and the Developer Platform and API Reference for building integrations.
> Help Center pages describe what a company admin sees. A reader's role can hide screens and actions; admins manage roles on Settings > Roles (/help/admin/settings/roles). If someone can't find a screen or button, their role's permissions are the first thing to check.
> Send people who need Fluid support to /help/getting-help. Don't invent support email addresses, phone numbers or response times.

# Give a site a database

> Turn on a Postgres database for a member's own site, create its tables, declare database access in config/access.json, and read and write rows from the site's script with fluid.fetch.

A member's own site can have a database. It is a Postgres database that only the site's owner, and the owner's own site script, can use. Use it for data a site keeps for itself, such as a list of notes or a reading list. This page covers how to turn it on, create tables, declare access, use it from the site's script, and what it costs and limits.

> [!NOTE]
>
> Member sites must be turned on for your company by Fluid. To ask for them, [contact support](https://docs.fluid.app/help/getting-help.md).

## Know what a site database is

* **It is a Postgres database.** The site owns its tables. You create them with schema statements, and the site's script reads and writes rows.
* **Only the owner uses it.** The site's owner, and the owner's own site script, are the only ones who reach it. See [Know who can use it](#know-who-can-use-it).
* **It is billed to the company.** The database runs on the company's hosting account and its hosting credits pay for it.
* **A site has at most one, and a company at most 20.** The cap counts every site database in the company.
* **Only a member's own site can have one.** A company site, a branch and a taken-down site can't.

The CLI turns the database on and off, creates tables and reads rows. It doesn't insert, change or delete rows. The site's script does that with `fluid.fetch`, and the [member API](https://docs.fluid.app/api/member-apis.md) does it for anything else.

The `database` commands always act as the member, as `--as member` does for the other [commands](https://docs.fluid.app/member-sites/cli.md#choose-the-login), so they take no `--as`. A person who isn't a rep at the company is refused before any request. Each command takes the site as its last, optional argument, by handle or id. It also takes `--dir <dir>` for a pulled folder. With neither, the site is the pulled folder in the current folder. Each takes `--json` to print only the API's answer as JSON.

## Turn it on

> [!WARNING]
>
> Turning on a database costs the company. Ask the company before you turn one on.

Turn it on and wait for it:

```bash theme={null}
fluid member-site database on --wait
```

The database is created in the background. Its state is `provisioning` until the first deploy finishes, then `live`. Only a `live` database whose `available` is `true` answers calls.

* **`--wait` checks for you.** It checks the status every three seconds until the database answers, ends in a state that can't serve, or `--timeout <seconds>` runs out. The timeout is 300 seconds by default and at most 3600. A database still being created when time is up keeps being created.
* **`status` checks without waiting.** `fluid member-site database status` prints the database's state, whether it answers calls now, its limits and what to do next. It sends nothing to the database itself, so it answers while the database is being created. A site with no database answers `404`.
* **Turning it on twice is refused.** A site whose database is `provisioning` or `live` answers `409`. A site whose database `failed`, was removed or was deleted gets a new, empty one.
* **A draft site can have one.** Turning it on works for a draft. Its tables and rows still wait for the publish below.

Without the CLI, use [Turn on a site's database](https://docs.fluid.app/api-reference/site-database/turn-on-a-sites-database.md) and [Show a site's database status](https://docs.fluid.app/api-reference/site-database/show-a-sites-database-status.md). The request takes no body.

## Read a 404 and the status

A `404` from a database call has more than one cause. Tell them apart by the call.

| You see | It means |
| - | - |
| `404` on `database status`, `tables` or `rows` before you turn the database on | The site has no database yet. This is normal. Turn it on |
| `404` on `database on` | Member sites isn't turned on for the company, or the site isn't a member's own: a company site, another member's site or a site that doesn't exist. A draft site is fine. A branch or a taken-down site answers `422` instead |
| `404` on `tables`, `sql` or `rows` while `status` shows `live` | The site is a draft or taken down, or the table doesn't exist. See [Publish the site first](#publish-the-site-first) |
| `409` with `database_unavailable` | The site has a database, but it can't serve now. Its details give the `state` and a `next_step` |
| `state` of `provisioning` | The database is still being created. Check `status` until it is `live` and `available` is `true` |
| `state` of `failed`, `pending_destroy`, `archived` or `discarded` | The database can't recover. Run `database on` again for a new one, or `database off` |

To tell a missing database from member sites being off, run `fluid member-site list --as member`. When member sites is off for the company, every member site request answers `404`, the list included. When the list works, the site has no database yet.

## Publish the site first

A draft or taken-down site's tables, schema statements and rows answer `404`, even while its database is `live`. `status` and turning the database off still answer, and so does turning it on for a draft.

Publish the site before you create tables:

```bash theme={null}
fluid member-site publish
```

Publishing is the site owner's decision. See [Publish, restore, copy and take down a member site](https://docs.fluid.app/member-sites/publishing.md).

## Create tables

Run one schema statement at a time with `database sql`. Give the statement as the argument, or put it in a file and pass `--file`. With `--file`, the only other argument is the site.

```bash theme={null}
fluid member-site database sql "CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL, status text NOT NULL DEFAULT 'open')"
fluid member-site database sql --file schema.sql rileys-shop
```

Then check what you made:

```bash theme={null}
fluid member-site database tables
```

`tables` lists the tables of the database's `public` schema and their columns. Each column shows its type, whether it can be null, its default and whether it is part of the primary key.

**Fluid accepts one statement of a schema form.** For example `CREATE TABLE`, `CREATE INDEX`, `ALTER TABLE` with one action, `DROP TABLE`, `DROP INDEX` and `COMMENT ON`.

**Fluid refuses these with a `422`:**

* Any statement that could read or copy rows: `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `CREATE TABLE ... AS`, `COPY`, `WITH` and the like.
* A second command in the same statement.
* A comment, and dollar quoting.
* A view, function, trigger, extension, role, schema or sequence.

The database looks for these words anywhere in the text. A default value or a comment that holds one is refused too.

A statement is at most 60,000 characters. A statement that runs longer than 3 seconds is stopped.

With the API, use [Run a schema statement on a site's database](https://docs.fluid.app/api-reference/site-database/run-a-schema-statement-on-a-sites-database.md) and [List the tables of a site's database](https://docs.fluid.app/api-reference/site-database/list-the-tables-of-a-sites-database.md).

To check what a script wrote, list a table's rows from the terminal:

```bash theme={null}
fluid member-site database rows notes --sort=-id --limit 10
```

`rows <table>` prints one page of rows and the cursor of the next page. It takes `--limit <n>` (1 to 100, 25 by default), `--sort <columns>`, `--cursor <cursor>` and `--filter <column>.<operator>=<value>`. With `--json`, it prints `{ "rows": [...], "next_cursor": "..." | null }`.

## Declare access

A site script reaches its database only for a scope the site declares in `config/access.json`. Without a declaration, an owner's script holds no `database` scope.

```json config/access.json theme={null}
{
  "uses": ["database: read", "database: write"]
}
```

* **`database: read`** covers the database's status, its tables and a table's rows.
* **`database: write`** covers inserting, changing and removing rows.
* **`write` doesn't include `read`.** Declare both when the script does both.
* **Turning the database on or off and running a schema statement have no scope.** A site's script can never do them, whatever it declares. See [Know who can use it](#know-who-can-use-it).

Run `fluid member-site lint` before you push. It checks each `fluid.fetch(path, { method })` call against the declaration and warns on a call whose scope the file lacks. It reads a path written as a string, or as a template literal that fills in only whole path segments, such as `` `/api/member/v2026-10/sites/${SITE_ID}/database/tables/notes/rows` ``. It warns about any other call, such as a path held in a variable or joined with `+`, because it can't read it. Then push, and publish.

A declaration is a draft until you publish. It takes effect when the site is published, and a publish that drops a scope refuses the next call. See [Declare what a member site uses](https://docs.fluid.app/member-sites/access-declarations.md) for how to write, publish and check the file.

## Use it from the site's script

A script reaches the database with [`fluid.fetch`](https://docs.fluid.app/member-sites/site-scripts), on a path that holds the site's id. Find the id with `fluid member-site list`. It isn't a secret.

The path of a database call is `/api/member/v2026-10/sites/<site-id>/database/...`. Fluid sends it as written. Write each path in the call itself, as the examples do, so lint can read it.

### List rows

```js assets/site.js theme={null}
const SITE_ID = "0192f4e5-6f7a-7b8c-9d0e-1f2a3b4c5d67";

async function listNotes(cursor) {
  const query = new URLSearchParams({
    sort: "-id",
    "page[limit]": "10",
    "filter[status][eq]": "open",
  });
  if (cursor) query.set("page[cursor]", cursor);

  const response = await fluid.fetch(
    `/api/member/v2026-10/sites/${SITE_ID}/database/tables/notes/rows?${query}`,
  );
  if (!response.ok) throw await databaseError(response);

  const { data, meta } = await response.json();
  // data: [{ id: 2, title: "Hello", status: "open" }, ...]
  // meta.pagination.next_cursor is null on the last page.
  return { notes: data, next: meta.pagination.next_cursor };
}
```

* **`sort`** is a comma-separated list of columns, at most 10, with a leading `-` for descending, such as `-id,title`. The order always ends with the table's primary key, so equal values keep a stable order.
* **`page[limit]`** is 1 to 100 rows, 25 when you leave it out.
* **`page[cursor]`** is the `meta.pagination.next_cursor` of the previous list. It is tied to the table, filters and sort it was issued for, so a different one is a `400`.
* **`filter[<column>][<operator>]`** takes `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in` and `is_null`. Filters are ANDed, at most 50. `in` takes one to 100 comma-separated values, such as `filter[id][in]=1,2,3`. `is_null` takes `true` or `false`. A filter on a column the table doesn't have is a `422`.
* **A call from a site script carries a query string of at most 2,048 characters.** Send a longer filter with the owner's token, outside the site.

See [List the rows of a table](https://docs.fluid.app/api-reference/site-database/list-the-rows-of-a-table.md).

### Insert rows

```js assets/site.js theme={null}
async function addNote(title) {
  const response = await fluid.fetch(
    `/api/member/v2026-10/sites/${SITE_ID}/database/tables/notes/rows`,
    {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ rows: [{ title }] }),
    },
  );
  if (!response.ok) throw await databaseError(response);
  return (await response.json()).data[0]; // { id: 3, title: "Hello", status: "open" }
}
```

An insert takes one to 100 rows, all or none, and answers with the inserted rows, including the columns the database filled in. A unique or foreign-key conflict is a `409` with the error `conflict`. See [Insert rows into a table](https://docs.fluid.app/api-reference/site-database/insert-rows-into-a-table.md).

### Change a row

```js assets/site.js theme={null}
async function renameNote(id, title) {
  const response = await fluid.fetch(
    `/api/member/v2026-10/sites/${SITE_ID}/database/tables/notes/rows/${id}`,
    {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ values: { title } }),
    },
  );
  if (!response.ok) throw await databaseError(response);
  return (await response.json()).data;
}
```

A row is addressed by the table's single-column primary key. The values can't name the primary key. A table with no single-column primary key answers `422`, and a key that doesn't exist answers `404`. See [Change a row](https://docs.fluid.app/api-reference/site-database/change-a-row.md).

### Remove a row

```js assets/site.js theme={null}
async function removeNote(id) {
  const response = await fluid.fetch(
    `/api/member/v2026-10/sites/${SITE_ID}/database/tables/notes/rows/${id}`,
    { method: "DELETE" },
  );
  if (!response.ok) throw await databaseError(response);
  // A removal answers 204 with an empty body. Don't call response.json().
}
```

See [Remove a row](https://docs.fluid.app/api-reference/site-database/remove-a-row.md).

### Handle the Response

`fluid.fetch` resolves to a `Response` for any HTTP status, so check `response.ok` first, as on [Read viewer data in site scripts](https://docs.fluid.app/member-sites/site-scripts.md#handle-the-response). The body of a refusal holds `error.details.error`. One answer needs its own handling: a `409` with the error `database_unavailable` means the database can't serve now. Its details carry the database's `state` and a `next_step`.

```js assets/site.js theme={null}
async function databaseError(response) {
  const body = await response.json().catch(() => ({}));
  const details = body.error?.details ?? {};

  if (response.status === 409 && details.error === "database_unavailable") {
    // The database is still being created, or can't serve.
    showMessage("Notes are not ready yet. Try again in a minute.");
    console.warn(`Database is ${details.state}: ${details.next_step}`);
  } else if (response.status === 403 && details.error === "member_site_scope_undeclared") {
    console.warn(`Declare "${details.scope}" in config/access.json`);
  } else {
    showMessage("We couldn't reach your notes.");
  }
  return new Error(`Database call failed (${response.status})`);
}
```

Wrap a call in `try` and `catch` so a failure keeps the page usable. A site script can't turn the database on, so it shows a message for `database_unavailable` and leaves the fix to the owner: wait while the state is `provisioning`, and in any other state turn the database on again with the CLI.

## Know who can use it

Only the owner can use a site's database. Everyone else is refused, whatever the site declares.

* **The owner's credential runs every command and call.** That is the member's own bearer token, which the CLI sends.
* **Only the owner's own site script uses it from a page.** That is the signed-in owner of a member-owned site, viewing it published, with the scope in the published `config/access.json`. An owner with no declaration holds no `database` scope.
* **Share holders and visitors are always refused.** `database: read` and `database: write` are scopes a share holder never gets, even when the site declares them. A guest, a member no share matches and an admin no share matches get nothing. The refusal is a `403` with the body `member_site_unavailable`. See [Know who gets data](https://docs.fluid.app/member-sites/site-scripts.md#know-who-gets-data) and [Know what a share never grants](https://docs.fluid.app/member-sites/sharing.md#know-what-a-share-never-grants).
* **Turning it on or off and running SQL never work from site code.** They answer `403` whether or not the site declares anything, so a page's script can't spend the company's credits, remove its own database or drop a table. They belong to the CLI and the owner's bearer.
* **An email-link session token is refused.** The member session token that order and subscription email links carry is refused by every database operation. A read-only portal token is refused the ones that write.

## Know the limits

| Limit | Value |
| - | - |
| Databases per company | 20 |
| Request body | 64 KiB |
| Answer read from the database | 256 KiB. A longer one is abandoned and answers `502` |
| Calls | 60 a minute for each company, member and site. More answers `429` |
| Rows in a page | 25 by default, at most 100 |
| Rows in one insert | At most 100, all or none |
| Rows a SQL statement returns | At most 100 |
| Time for one operation | 3 seconds |
| SQL statement | One statement, at most 60,000 characters |

`fluid member-site database status` prints the limits the API reports.

## Turn it off, delete the site or take it down

> [!WARNING]
>
> Turning off a database deletes its tables and rows. It can't be undone.

* **Turning it off deletes the data.** `fluid member-site database off` asks first on a terminal. Where there is no terminal to ask on, it refuses unless you pass `--yes`. Its billing stops now, and the site can turn on a new, empty database afterwards. See [Turn off a site's database](https://docs.fluid.app/api-reference/site-database/turn-off-a-sites-database.md).
* **Deleting the site deletes the database and its data.** The database is handed to the same teardown as a turn-off.
* **A take-down doesn't turn the database off.** The database keeps running and keeps its data, and its billing doesn't stop. While the site is taken down, its tables, schema statements and rows answer `404`, as for a draft, until the site is published again. A taken-down site can't be published again, and its database can't be turned on.

## Fix common errors

The CLI turns each API answer into one message and a non-zero exit code. A script sees the status and the `error.details.error` code.

| You see | Why | What to do |
| - | - | - |
| `404` | The site has no database, or its tables and rows are asked for while the site isn't published, or the table doesn't exist | Turn on the database, publish the site, or list the tables |
| `401` | The login wasn't accepted | Use the member's own login. See [Choose the login](https://docs.fluid.app/member-sites/cli.md#choose-the-login) |
| `402` with `credits_exhausted` or `billing_unresolved` | The company has no hosting credits left, or its billing needs attention | Ask the company to resolve it before you turn the database on |
| `403` | The caller isn't the owner, the credential is an email-link session token or a read-only token on a write, or a site script called turn on, turn off or SQL | Use the owner's credential from the CLI. A script can't do these |
| `403` with `member_site_scope_undeclared` | The site's published declaration lacks the scope, which `details.scope` names | Declare it, push and publish |
| `409` with `exists` | The site already has a database, or one is being created | Check it with `database status` |
| `409` with `database_busy` | A step of creating the database held it. Nothing changed | Run the command again |
| `409` with `database_unavailable` | The database isn't `live`, so nothing was sent to it. `details.state` and `details.next_step` say what to do | While it is `provisioning`, wait and check `database status`. In any other state, run `database on` again, or turn it off |
| `409` with `conflict` | A unique or foreign-key conflict in the statement or the insert | Change the values |
| `422` with `not_eligible` | A branch or a taken-down site can't have a database | Use a member's own site that isn't taken down |
| `422` with `backend_limit_reached` | The company holds the most databases it may | Turn one off to make room |
| `422` with `invalid_statement` | The statement isn't a schema statement the database accepts | Send one schema statement. See [Create tables](#create-tables) |
| `400` with `invalid_cursor` | The cursor isn't one the database issued for this table, filters and sort | Start again without a cursor |
| `413` or `429` | The request is over 64 KiB, or there were more than 60 calls a minute | Send less, or wait a minute |
| `502` with `provisioning_failed` | A step of creating the database failed. Nothing was kept | Ask again with `database on` |
| `503` with `template_unavailable` or `admission_unavailable` | Nothing was created | Try again later |

A `404` answers the same for a company without member sites, a missing site and another owner's site. The CLI never retries it. It retries a read that fails with `502`, `503` or `504` twice, and never retries a write.

## Use the API directly

Each operation has a generated page in the API Reference. They all take the owner's bearer token, and the site's id is in the path.

| Task | CLI | Operation |
| - | - | - |
| Turn it on | `database on` | [Turn on a site's database](https://docs.fluid.app/api-reference/site-database/turn-on-a-sites-database.md) |
| Check it | `database status` | [Show a site's database status](https://docs.fluid.app/api-reference/site-database/show-a-sites-database-status.md) |
| Turn it off | `database off` | [Turn off a site's database](https://docs.fluid.app/api-reference/site-database/turn-off-a-sites-database.md) |
| List the tables | `database tables` | [List the tables of a site's database](https://docs.fluid.app/api-reference/site-database/list-the-tables-of-a-sites-database.md) |
| Run a schema statement | `database sql` | [Run a schema statement on a site's database](https://docs.fluid.app/api-reference/site-database/run-a-schema-statement-on-a-sites-database.md) |
| List rows | `database rows` | [List the rows of a table](https://docs.fluid.app/api-reference/site-database/list-the-rows-of-a-table.md) |
| Insert rows | Not available | [Insert rows into a table](https://docs.fluid.app/api-reference/site-database/insert-rows-into-a-table.md) |
| Change a row | Not available | [Change a row](https://docs.fluid.app/api-reference/site-database/change-a-row.md) |
| Remove a row | Not available | [Remove a row](https://docs.fluid.app/api-reference/site-database/remove-a-row.md) |

## Next steps

* [Read viewer data in site scripts](https://docs.fluid.app/member-sites/site-scripts.md) covers `window.fluid.fetch`.
* [Declare what a member site uses](https://docs.fluid.app/member-sites/access-declarations.md) covers `config/access.json`.
* [Member site CLI](https://docs.fluid.app/member-sites/cli.md) covers the other `fluid member-site` commands.
* [Publish, restore, copy and take down a member site](https://docs.fluid.app/member-sites/publishing.md) covers publishing and take-down.


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