# Realms (API Isolation)

**Page:** foundation/hoody-api/realms

[Download Raw Markdown](./foundation/hoody-api/realms.md)

---

# Realms (API Isolation)

In Hoody, **Realms are not container networks**.

Realms are an **API isolation mechanism** that lets you scope *visibility* and *control* of resources (projects, containers, servers, etc.) using:

- a **realm-scoped API hostname**: `https://{realmId}.api.hoody.icu`
- **realm membership** on resources: `realm_ids: string[]`
- optional **realm restrictions** on Auth Tokens: `realm_ids` + `allow_no_realm`

This is primarily about preventing mistakes (especially with automation/AI) and enabling multi-tenant isolation.

## What a Realm is (and is not)

### A Realm *is*

- A **24-hex identifier** (e.g. `507f1f77bcf86cd799439011`) used as an isolation label.
- A **filter applied at the Hoody API layer**.
- A way to ensure an Auth Token only operates on *the intended subset* of resources.

### A Realm is *not*

- A private L2/L3 network for container traffic.
- A DNS/service-discovery network segment.
- A firewall boundary.

If you’re trying to control **container-to-internet** or **container-to-container** networking, use:

- [`Container Network`](/api/container-network/) (proxy/VPN routing)
- [`Container Firewall`](/api/container-firewall/) (host-enforced ingress/egress rules)

## Realm-scoped API hosts

### Unscoped (base) API

```
https://api.hoody.icu
```

Using the base host means **no realm scoping is applied by hostname**.

### Scoped by realm (subdomain)

```
https://{realmId}.api.hoody.icu
```

The `{realmId}` label must be a **24-hex ID** (lowercase). Any other first label — including short/long labels, non-hex strings, or IP literals — is **silently ignored** (the request is simply treated as unscoped, like the base host), not rejected.

When you use a realm-scoped host:

- **Read operations** typically return only resources whose `realm_ids` contains that `{realmId}`.
- **Write operations** will automatically **merge the subdomain realm into `realm_ids`** when creating/updating many resources.

### Non-realm subdomains (e.g. `default`)

```
https://default.api.hoody.icu
```

`default` is **not** a special keyword — it's simply a label that isn't a 24-hex realm ID, so it falls into the "ignored" bucket and the request behaves exactly like the unscoped base host `api.hoody.icu`. The same is true of any other non-hex subdomain.

## realm_ids: how resources participate

Many Hoody resources include a `realm_ids: string[]` field.

- `realm_ids: []` means the resource is **not assigned to any realm** (unscoped).
- `realm_ids: ["<realmA>"]` means the resource belongs to **realm A**.
- `realm_ids: ["<realmA>", "<realmB>"]` means **multi-realm membership** (the resource can be visible/usable from multiple realm scopes).

### Common patterns

1. **One realm per environment**
   - production realm ID
   - staging realm ID
   - development realm ID

2. **One realm per tenant/client**
   - tenant A realm ID
   - tenant B realm ID

3. **One realm per automation/agent** (safest)
   - each agent token only sees one realm → fewer “wrong container” incidents

## Auth Tokens: restricting by realm

Auth Tokens can be restricted so they only work within certain realms.

Key fields:

- `realm_ids: string[]`
- `allow_no_realm: boolean`

Behavior (high-level):

- If `realm_ids` is non-empty, the token is valid only for those realm IDs.
- If `allow_no_realm` is `false`, the token cannot be used on the base host.
- If `realm_ids` is non-empty **or** `allow_no_realm` is `false`, resource operations require a realm-scoped hostname.
- If `realm_ids` is empty and `allow_no_realm` is `true`, the token is not realm-restricted.

### Bootstrap for Realm Discovery

Token-only clients can call:

- [`GET /api/v1/auth/tokens/me`](/api/auth-tokens/)

on `https://api.hoody.icu` to discover:

- `restrictions.allowed_realm_ids`
- `restrictions.requires_realm_scope`
- `restrictions.active_realm_id`

This bootstrap exception is for introspection only, not for general resource access.

## Creation and Update Semantics

### Projects

- `POST /api/v1/projects` merges the scoped realm into `realm_ids` when called on `{realmId}.api.hoody.icu`.
- Realm-restricted auth tokens cannot create projects in other realms; created projects are forced to the active scoped realm.
- `PATCH /api/v1/projects/{id}` preserves the scoped realm when `realm_ids` is updated.
- Realm-restricted tokens cannot modify project `realm_ids`.

### Containers

- `POST /api/v1/projects/{id}/containers` requires the target project to already belong to the scoped realm (if scoped).
- Container `realm_ids` merge the scoped realm.
- Realm-restricted tokens cannot assign container realms outside the active scoped realm.
- `PATCH /api/v1/containers/{id}` blocks `realm_ids` updates for realm-restricted tokens.

## Delegating containers to external parties (freelancers, auditors, support)

Realms are a practical way to **hand off access to a specific set of containers** without exposing the rest of your account.

The pattern is:

1. Put the container(s) you want to share into a dedicated realm by setting `realm_ids`.
2. Create a **realm-restricted Auth Token** with:
   - `realm_ids: ["<thatRealmId>"]`
   - `allow_no_realm: false` (so it can’t be used on the unscoped base host)
3. Share the token + realm-scoped base URL with the external party:
   - `https://{realmId}.api.hoody.icu`
4. When the work is complete, **disable or delete** the token.

Example: create a time-boxed token restricted to a single realm:


  
    ```bash
    # Create a realm-restricted auth token for a freelancer
    hoody auth create \
      --alias "freelancer-debug-access" \
      --expires-at "2026-04-19T00:00:00Z" \
      --ip-whitelist "203.0.113.44" \
      --realm-ids "507f1f77bcf86cd799439011" \
      --no-allow-no-realm

    # Use the token with realm-scoped host
    hoody --base-url "https://507f1f77bcf86cd799439011.api.hoody.icu" \
      containers list
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

    const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });

    // Create a realm-restricted auth token
    const token = await client.api.authTokens.create({
      alias: 'freelancer-debug-access',
      expires_at: '2026-04-19T00:00:00Z',
      ip_whitelist: ['203.0.113.44'],
      realm_ids: ['507f1f77bcf86cd799439011'],
      allow_no_realm: false,
    });

    // Use realm-scoped client
    const realmClient = new HoodyClient({
      baseURL: 'https://507f1f77bcf86cd799439011.api.hoody.icu',
      token: token.data.token,
    });
    const containers = await realmClient.api.containers.list();
    ```
  
  
    ```bash
    # Create a realm-restricted auth token
    curl -X POST "https://api.hoody.icu/api/v1/auth/tokens" \
      -H "Authorization: Bearer $HOODY_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "alias": "freelancer-debug-access",
        "expires_at": "2026-04-19T00:00:00Z",
        "ip_whitelist": ["203.0.113.44"],
        "realm_ids": ["507f1f77bcf86cd799439011"],
        "allow_no_realm": false
      }'

    # Use the token with realm-scoped host
    curl -X GET "https://507f1f77bcf86cd799439011.api.hoody.icu/api/v1/containers" \
      -H "Authorization: Bearer hdy_Abc123XyZ..."
    ```
  




Example: use that token (note the realm-scoped host):

```bash
curl -X GET "https://507f1f77bcf86cd799439011.api.hoody.icu/api/v1/containers" \
  -H "Authorization: Bearer hdy_Abc123XyZ..."
```

## API Endpoints Summary


  
    ```bash
    # List realm IDs associated with your resources
    hoody realms list

    # List containers filtered by realm
    hoody --base-url "https://507f1f77bcf86cd799439011.api.hoody.icu" \
      containers list
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

    const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });

    // List realm IDs
    const realms = await client.api.realms.list();
    console.log(realms.data);

    // Use realm-scoped client
    const realmClient = new HoodyClient({
      baseURL: 'https://507f1f77bcf86cd799439011.api.hoody.icu',
      token: process.env.HOODY_TOKEN
    });
    const containers = await realmClient.api.containers.list();
    ```
  
  
    ```bash
    # List realm IDs associated with your resources
    curl "https://api.hoody.icu/api/v1/realms" \
      -H "Authorization: Bearer $HOODY_TOKEN"

    # List containers scoped to a realm
    curl "https://507f1f77bcf86cd799439011.api.hoody.icu/api/v1/containers" \
      -H "Authorization: Bearer $HOODY_TOKEN"
    ```
  


Many list endpoints accept `realm_id` as a query parameter to filter results by realm membership.

## Use Cases

1. **Prevent automation mistakes**: Make a token that can only touch “prod”. Your CI can’t accidentally delete dev containers.
2. **Tenant isolation**: One token per client, restricted to that client’s realm.
3. **AI agent sandboxing**: Give each agent a realm-restricted token so it can’t even *see* other realms.
4. **External delegation**: Give a freelancer/auditor/support engineer a realm-restricted token that only exposes the containers they need to work on.

## Best Practices

- Prefer **realm-scoped hosts** for automation: `https://{realmId}.api.hoody.icu`.
- Use **separate tokens** per realm and per app (easier auditing + revocation).
- For external delegation, combine realm restriction with **short expirations** and **IP allowlists**.
- Avoid multi-realm membership unless you truly need it (it weakens isolation boundaries).

## Useful Questions

### Do Realms change container networking?

No. Realms only affect **Hoody API visibility and access control**. Networking is handled by proxy/VPN configuration and firewall rules.

### Can a resource belong to multiple realms?

Yes. Many resources support `realm_ids: string[]` and can be assigned to multiple realm IDs.

### How do I discover which realm IDs I’m using?

Call [`GET /api/v1/realms`](/api/realms/). It deduplicates realm IDs found across your resources.

## Troubleshooting

### 403: “This token requires a realm-scoped URL”

Your Auth Token likely has `realm_ids` configured and/or `allow_no_realm: false`. Use:

```
https://{realmId}.api.hoody.icu
```

instead of `https://api.hoody.icu`.

### 403: “token not valid for realm”

Your Auth Token’s `realm_ids` allowlist does not include the `{realmId}` you’re using in the hostname.

### 403: “Resource is not in requested realm”

The requested project/container/share does not belong to the realm in the URL. Use the correct realm host or move the resource realm membership first.

## What's Next

- [`Realms API Reference`](/api/realms/)
- [`Auth Tokens`](/api/auth-tokens/)
- [`Create/Edit/Delete Containers`](/foundation/containers/create-edit-delete/)