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

# Organizations & teams

> One shared plan and balance for a team: members and invites, which wallet a sandbox bills, the sandboxes your team shares, per-member caps, and moving a personal plan in.

<video controls playsInline preload="metadata" poster="/videos/organizations.jpg" src="https://mintcdn.com/ariana-1e97e6c3/GM_ek11Akew5pcll/videos/organizations.mp4?fit=max&auto=format&n=GM_ek11Akew5pcll&q=85&s=cca0a5857b2d54ce333862610845d4e3" className="w-full aspect-video rounded-xl" data-path="videos/organizations.mp4" />

An organization is a team account: one plan, one balance, and members who run sandboxes against it. Every member sees every sandbox the organization pays for, and can use the ones that hold nobody's personal logins. Snapshots and environments stay with the person who made them.

## Members and invites

The owner invites people by email. They join from the link in the email, with any sign-in method, and the organization shows up in their `boat org list` and in the dashboard's **Viewing** dropdown.

<CodeGroup>
  ```bash CLI theme={null}
  boat org create acme                 # you become its owner
  boat org switch acme
  boat org invite dana@example.com     # owner only
  boat org members                     # members and pending invites
  boat org transfer dana               # make dana the owner; you become a member
  ```
</CodeGroup>

Removing a member, changing roles and per-member caps are on the [Organization](https://boat.dev/dashboard?tab=org) tab of the dashboard. When a member leaves, the sandboxes they created go back to their personal billing.

## Which wallet a sandbox bills

Every account has one **active wallet**: personal until you change it. A new sandbox bills the wallet the request names; a request that names none bills the active wallet. It is one setting on the account, so the dashboard, the CLI and a bare API key all bill the same place, and `GET /limits` reads the wallet a create would bill. The wallet a sandbox bills is fixed when it is created.

An organization is named by its id (`team_…`) or by its name, exactly as `GET /orgs` / `boat org list` show it (case does not matter). `personal` is your own account. Only two organizations sharing a name need the id (`409 ambiguous_org`).

<CodeGroup>
  ```bash CLI theme={null}
  boat org                     # the wallet in effect right now
  boat org list                # organizations you belong to, ids and names
  boat org switch acme         # active wallet = acme, for the CLI, the dashboard and the API
  boat org switch personal     # back to your own account
  boat --org acme new          # bill one create to acme without switching
  ```

  ```bash curl theme={null}
  curl -sS "$BOAT_API_BASE/orgs" -H "Authorization: Bearer $BOAT_API_KEY"
  # -> orgs: [{ id, name, type, role, active }, ...]

  curl -sS -X PATCH "$BOAT_API_BASE/orgs/active" \
    -H "Authorization: Bearer $BOAT_API_KEY" -H "Content-Type: application/json" \
    -d '{ "org": "acme" }'                  # or the team_… id, or "personal"

  # one call elsewhere: header, query, or body
  curl -sS -X POST "$BOAT_API_BASE/sandboxes" -H "X-Boat-Org: acme" ...
  curl -sS "$BOAT_API_BASE/limits?org=acme" ...
  curl -sS -X POST "$BOAT_API_BASE/sandboxes" -d '{ "org": "acme" }' ...
  ```

  ```ts TypeScript theme={null}
  const { orgs } = await sandbox.listOrganizations();          // ids, names, active
  await sandbox.setActiveOrganization({ org: "acme" });
  await sandbox.create({ org: "acme" }); // one sandbox elsewhere
  ```

  ```python Python theme={null}
  from boat_sdk.models.active_org_update_request import ActiveOrgUpdateRequest
  from boat_sdk.models.create_sandbox_request import CreateSandboxRequest

  orgs = sandbox.list_organizations().orgs                     # ids, names, active
  sandbox.set_active_organization(ActiveOrgUpdateRequest(org="acme"))
  sandbox.create(CreateSandboxRequest(org="acme"))             # one sandbox elsewhere
  ```
</CodeGroup>

In the dashboard, the sidebar shows the active wallet; **Change** sets it for the account, and the CLI and API follow. The **Viewing** dropdown at the top of a page only changes what that page shows, and opens on the active wallet.

## Sandboxes your team shares

In an organization's scope, `boat list`, `GET /sandboxes` and the dashboard list your own sandboxes **and every sandbox the organization pays for**, whoever created it. Each one says who made it (`createdBy`) and what you can do with it (`access`):

| `access` | Who | What you can do |
| - | - | - |
| `owner` | You created it | Everything |
| `use` | A teammate's sandbox that holds none of their personal logins | Open it, SSH, run commands, read and write files, prompt its agent, open ports, resume and stop it |
| `view` | A teammate's sandbox that still holds their personal logins | See it, its usage, and stop it |

**Why `view` exists.** A sandbox receives its creator's GitHub token, Claude and Codex logins and environment secrets when its environment passes them. Anyone with a shell in it could act as that person, so a teammate only gets a shell once none of those are on it. A sandbox created with `--no-env` is `use` for every member from the start. That is the setup to pick for agents the whole team runs: give them the team's own model keys with `--env`, not a person's logins.

**Sharing one that holds your logins.** Its creator runs `share`. Their GitHub token, model logins, secret files and the sandbox's own CLI key are never pushed to it again (it becomes `noEnv`) and are wiped off its disk when it next starts. Files and installs stay. It cannot be undone. A sandbox that is running when you share it still has your logins in the memory of what runs on it, so it stays `view` for your team until you stop and resume it (`restartRequired: true` in the response).

<CodeGroup>
  ```bash CLI theme={null}
  boat org switch acme               # the org's scope: boat list shows its sandboxes too
  boat list
  # bx_7k2m9qpd  running  2h 10m  research-agent  [org: acme]  by alex  view only: holds alex's logins
  # bx_4tr8wz3c  running  -       support-agent   [org: acme]  by alex
  boat stop bx_7k2m9qpd              # alex, the creator
  boat share bx_7k2m9qpd
  boat resume bx_7k2m9qpd            # comes back without alex's logins: every member can use it
  ```

  ```bash curl theme={null}
  curl -sS "$BOAT_API_BASE/sandboxes" -H "Authorization: Bearer $BOAT_API_KEY" -H "X-Boat-Org: acme"
  # -> sandboxes: [{ id, name, state, createdBy, access, holdsCreatorLogins, team, ... }]

  curl -sS -X POST "$BOAT_API_BASE/sandboxes/bx_7k2m9qpd/share" -H "Authorization: Bearer $BOAT_API_KEY"
  # -> { sandbox: { ... }, restartRequired: true }  when it was running: stop + resume it
  ```

  ```ts TypeScript theme={null}
  const { sandboxes } = await sandbox.sandboxes({ org: "acme" });
  for (const s of sandboxes) console.log(s.name, s.createdBy, s.access);
  await sandbox.share({ sandboxId: "bx_7k2m9qpd" }); // creator only
  ```

  ```python Python theme={null}
  page = sandbox.sandboxes(org="acme")
  for s in page.sandboxes:
      print(s.name, s.created_by, s.access)
  sandbox.share(sandbox_id="bx_7k2m9qpd")  # creator only
  ```
</CodeGroup>

In the dashboard, teammates' rows say **by alex**, **view only** when they still hold alex's logins, and the creator's own rows read **private** until they pick **Share with org** in the row menu.

A teammate who tries to use a `view` sandbox gets `403 sandbox_private` naming whose logins it holds. Some things stay with the creator (`403 owner_only`): forking, deleting, changing its settings (name, subdomain, auto-stop), and any stop that throws data away (`--force`, or any stop of a sandbox with snapshots off), which the organization owner can also do.

## Limits and per-member caps

The start-rate and concurrency numbers on the plan are **one shared pool for the whole organization**, multiplied by its seats: a 5-seat organization on the \$20 plan gets 500 concurrent sandboxes, 60 starts/min, 300/hour, 1000/day. If one member burns the hourly start budget, every other member's `new`, `fork` and `resume` billed to the organization is refused until the window rolls. Personal sandboxes use the member's own personal limits. The seat multiplier only holds while the organization's plan is active; without one, leftover credit packs still run sandboxes at a single seat's limits.

One shared balance means one member can spend it all, so the owner can cap each member on the [Organization](https://boat.dev/dashboard?tab=org) tab (both unlimited by default):

| Cap | Limits |
| - | - |
| Usage cap | That member's organization-billed machine time per billing window |
| Concurrent sandboxes | How many organization-billed sandboxes that member can run at once |

Caps only touch organization-billed sandboxes. A sandbox counts against its **creator's** caps, also when a teammate resumes it. Past a usage cap, `new`, `fork` and `resume` answer `402 team_member_cap_reached`; past a concurrent-sandbox cap, `429 member_limit_reached`. Either way the member's organization sandboxes are snapshotted and stopped within about a minute; nothing is lost. Raising the cap, or the billing window renewing, makes them resumable again.

## Moving a personal plan in

If you paid personally before the organization existed, do not cancel the personal plan by hand: sandboxes that bill your personal account would stop with it. Move instead. Every sandbox billed to your personal account bills the organization from that moment, your personal plan ends the same day with the unused share of the month refunded to your card, and credit packs you bought stay on your personal account.

<CodeGroup>
  ```bash CLI theme={null}
  boat --org acme billing plan 20 --move-personal   # first org plan, move included once it is paid
  boat --org acme org migrate                       # org already on a plan
  ```

  ```bash curl theme={null}
  curl -sS -X POST "$BOAT_API_BASE/billing/move-to-org" \
    -H "Authorization: Bearer $BOAT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"teamId": "team_..."}'
  ```
</CodeGroup>

The dashboard offers the same move on the organization's Billing tab and inside the personal cancel-plan dialog.

## Where to do what

| | CLI | API | SDKs | Dashboard |
| - | - | - | - | - |
| See your organizations | `boat org list` | `GET /orgs` | `listOrganizations` | **Viewing** dropdown |
| Set the active wallet | `boat org switch <org>` | `PATCH /orgs/active` | `setActiveOrganization` | sidebar **Active wallet > Change** |
| Bill one sandbox elsewhere | `boat --org acme new` | `org` on `POST /sandboxes`, or `X-Boat-Org` | `org` on `create` | change the active wallet |
| Create, transfer, delete | `boat org create` / `transfer` / `delete` | not available | not available | [Organization](https://boat.dev/dashboard?tab=org) |
| Members and invites | `boat org members` / `boat org invite` | not available | not available | [Organization](https://boat.dev/dashboard?tab=org) |
| Remove members, caps | not available | not available | not available | [Organization](https://boat.dev/dashboard?tab=org) |
| See and share team sandboxes | `boat list` / `boat share` | `GET /sandboxes` / `POST /sandboxes/{id}/share` | `sandboxes` / `share` | [Sandboxes](https://boat.dev/dashboard?tab=sandboxes), row menu |
| Org plan, extra time, auto-refill | `boat --org acme billing …` | `/billing/*` with `teamId` | not available | [Billing](https://boat.dev/dashboard?tab=billing) viewing the org |

Plans, credit packs and running out work the same on an organization as on a personal account: see [Billing details](/billing).
