# Teams, roles and the audit log

> Who can do what in a moatbox team, how invites, removals and seats work, and how to read the audit log.

Every space belongs to a team. Each person in a team has one role: **owner**, **admin** or **member**. Owners and admins manage the team; members use its spaces.

## Roles

| Action | Owner | Admin | Member |
| --- | --- | --- | --- |
| See the team's spaces, runs, snapshots and members | Yes | Yes | Yes |
| Start runs, sleep and wake spaces | Yes | Yes | Yes |
| Browse and download files from snapshots | Yes | Yes | Yes |
| Turn command and process history on or off for one space | Yes | Yes | Yes |
| Leave the team | Yes, unless last owner | Yes | Yes |
| Create, fork and delete spaces; restore them from the trash | Yes | Yes | No |
| Change a space's settings | Yes | Yes | No |
| Reset, restore and undo; save, delete and share snapshots | Yes | Yes | No |
| Set the team's privacy policy and a space's privacy | Yes | Yes | No |
| Change environments and team-wide credentials | Yes | Yes | No |
| Manage billing and the spend cap | Yes | Yes | No |
| Manage webhooks and telemetry | Yes | Yes | No |
| Connect GitHub for CI and change CI settings | Yes | Yes | No |
| Link machines; connect a space to a tailnet | Yes | Yes | No |
| Invite people and revoke invites | Yes | Yes | No |
| Remove members and admins | Yes | Yes | No |
| Remove an owner | Yes | No | No |
| Change roles | Yes | No | No |
| See the whole audit log | Yes | Yes | Own actions and space events |

A team always keeps at least one owner. moatbox refuses to demote or remove the last owner, and the last owner cannot leave.

## Invite people

Inviting needs the Team plan. An owner or admin types an email in **Settings > Team** and presses **Invite**.

The person gets an email from moatbox with an **Accept invite** link. The link opens **Team invite** in the dashboard, where they press **Join the team**. They must sign in with the address you invited. The invite expires after 7 days. New people join as members.

An invite stops working when:

- an owner or admin revokes it
- the person who sent it becomes a member or leaves the team
- the person who sent it closes their account

## Remove people and change roles

Owners and admins remove people. Admins can remove members and other admins; only owners can remove an owner. Anyone can remove themselves to leave.

When someone leaves or is removed, moatbox revokes their API keys for that team and the pending invites they sent or received.

Only owners change roles. When an owner makes someone a member, moatbox revokes the invites that person sent.

The dashboard lists members and sends invites. Role changes, removals and invite revokes go through the API, from a signed-in browser session. No API key can call them.

| Method and path | Body | Does |
| --- | --- | --- |
| `POST /api/v1/teams/{team}/invites` | `{"email": "..."}` | Invite someone |
| `DELETE /api/v1/invites/{id}` | | Revoke an invite |
| `POST /api/v1/invites/accept` | `{"token": "..."}` | Accept an invite |
| `PATCH /api/v1/teams/{team}/members/{user}` | `{"role": "owner" \| "admin" \| "member"}` | Change a role |
| `DELETE /api/v1/teams/{team}/members/{user}` | | Remove someone, or leave |
| `GET /api/v1/teams/{team}/members` | | List members with roles and join dates |

## Seats

On the Team plan, the plan includes a number of seats. Each member past that number is an extra seat on the team's subscription. moatbox updates the seat count when someone joins or leaves, with proration. Each extra seat also raises the team's included space-hours and the number of boxes the team can run at once.

**Settings > Team** shows how many seats you use and how many the plan includes.

## The audit log

moatbox records who did what in the team: invites, joins, removals and role changes, space creates, deletes, forks, resets and restores, snapshot saves, downloads and shares, privacy and monitoring changes, CI connects and refused jobs, API key writes, and more. Each entry has a time, the actor, the space if there is one, a kind such as `member.invited` or `snapshot.restored`, and a short summary. If an API key did it, the entry names the key.

Open **Audit** in the dashboard. Filter by person, space, event type (Approvals, Runs, SSH sessions, File transfers, Credentials, Integration rules, Members, Invites, Logins) and time frame. **Export CSV** downloads what the filters show.

Owners and admins see every entry. Members see entries about a space and their own actions.

moatbox keeps the audit log while the team exists, also under zero data retention. See [Privacy](https://docs.moatbox.dev/privacy.md).

### Audit API

```bash
curl "https://app.moatbox.dev/api/v1/teams/$TEAM_ID/audit?kind=member&since=2026-11-01T00:00:00Z" \
  -H "Authorization: Bearer $MOATBOX_API_KEY"
```

The key needs the `team.read` action. Query parameters:

| Parameter | Meaning |
| --- | --- |
| `space` | A space's slug |
| `actor` | A user id |
| `kind` | An exact kind, such as `member.removed`, or the part before the dot, such as `member` |
| `key` | An API key id |
| `since`, `until` | RFC 3339 times |
| `limit` | 1 to 200; 50 by default |
| `before` | The `next` cursor from the previous page |
| `format=csv` | CSV with up to 10,000 rows per request |

The JSON answer has `events` and `next`. A CSV answer sends the next cursor in the `X-Next-Cursor` header and a `Link` header with `rel="next"`. CSV columns: `id`, `at`, `space`, `actor`, `kind`, `summary`, `key_id`, `key_name`.

API keys are covered in [API keys](https://docs.moatbox.dev/api-keys.md).
