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

# Databases and users

> Create Airhouse databases and users with the Admin API, and onboard users of your platform.

When you run Airhouse with the control plane enabled, you manage databases and their users through the **Admin API**. Each database is fully isolated, with its own catalog and its own storage prefix. A user belongs to exactly one database.

<Note>
  In the Admin API, databases are called **tenants**, so paths look like `/admin/v1/tenants/{id}`. A tenant's `id` is the database name clients connect to.
</Note>

## Before you start

* The server must have the control plane configured. See [Control plane](../reference/configuration#control-plane) in the configuration reference.
* The Admin API is served on the HTTP port (default `8080`) under `/admin/v1/`.
* Every request needs the admin token in the `Authorization` header:

```text theme={null}
Authorization: Bearer <admin token>
```

<Warning>
  The admin token has full control over every database. Keep it on your servers, never in client applications. To let an application create credentials for its own users, give it a [service account](./service-accounts) instead.
</Warning>

## Databases

### Create a database

```bash theme={null}
curl -X POST http://localhost:8080/admin/v1/tenants \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"id": "acme"}'
```

The `id` may contain ASCII letters, digits, `_`, and `-`, up to 63 characters. Airhouse creates the database's catalog and storage location and returns `201 Created`. Storage uses the bucket configured on the server. Don't send `bucket` or `prefix` in the request.

<Warning>
  The response includes internal connection details for the database's catalog, including credentials. Treat it as a secret: don't log it, and never return it to end users. End users connect through port `5445` with their own username and password.
</Warning>

### List and get databases

```bash theme={null}
curl http://localhost:8080/admin/v1/tenants \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN"

curl http://localhost:8080/admin/v1/tenants/acme \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN"
```

### Delete a database

```bash theme={null}
curl -X DELETE http://localhost:8080/admin/v1/tenants/acme \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN"
```

Deleting a database removes its catalog, its users, and its service accounts, and returns `204 No Content`, even if the database didn't exist.

<Warning>
  Deleting a database can't be undone: every table definition and snapshot in its catalog is lost. The Parquet files in object storage are not deleted automatically. Remove them from the bucket yourself if you need to.
</Warning>

## Users

### Create a user

```bash theme={null}
curl -X POST http://localhost:8080/admin/v1/tenants/acme/users \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"username": "alice", "password": "s3cr3t", "role": "writer"}'
```

| Field | Required | Description |
| - | - | - |
| `username` | Yes | Login name, unique within the database |
| `password` | Yes | Stored as a SCRAM-SHA-256 verifier, never in plain text |
| `role` | No | `reader` (default), `writer`, or `admin`. Any other value returns `400`. |

Response (`201 Created`):

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "acme",
  "username": "alice",
  "role": "writer",
  "created_at": "2026-04-29T10:01:00Z"
}
```

### List users

```bash theme={null}
curl http://localhost:8080/admin/v1/tenants/acme/users \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN"
```

The list contains users created with this endpoint. Short-lived credentials minted by [service accounts](./service-accounts) aren't included.

### Delete a user

```bash theme={null}
curl -X DELETE http://localhost:8080/admin/v1/tenants/acme/users/alice \
  -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN"
```

Returns `204 No Content` if the user existed, or `404` if it didn't.

## Onboard a customer of your platform

A typical onboarding flow creates a database and a first user, then hands the user their connection details:

<Steps>
  <Step title="Create the database">
    ```bash theme={null}
    curl -X POST "$AIRHOUSE_HTTP/admin/v1/tenants" \
      -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{"id": "acme"}'
    ```
  </Step>

  <Step title="Create a user">
    ```bash theme={null}
    curl -X POST "$AIRHOUSE_HTTP/admin/v1/tenants/acme/users" \
      -H "Authorization: Bearer $AIRHOUSE_ADMIN_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{"username": "alice", "password": "s3cr3t", "role": "reader"}'
    ```
  </Step>

  <Step title="Share the connection details">
    ```text theme={null}
    host=airhouse.example.com port=5445 dbname=acme user=alice password=s3cr3t
    ```

    If the user connects to a database that doesn't exist, the connection fails with `database "acme" does not exist` (SQLSTATE `3D000`).
  </Step>
</Steps>

To offboard, delete the user, then the database.

For the complete list of endpoints and status codes, see the [Admin API reference](../reference/admin-api).


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