Account & teams
Account and team resources sit at the top of the object graph. Your account owns API keys and personal sites; teams own members, projects, sites, invites, an audit trail, and a plan. These resources are product-agnostic — they look the same whether your sites run WordPress, static, or wasm.
Account
Section titled “Account”Your account is the principal behind a personal key.
GET /v1/account
Section titled “GET /v1/account”account:read Retrieve the authenticated account — profile, plan, and the scopes the calling credential holds, for permission introspection.
curl https://api.managed.dev/v1/account \ -H "Authorization: Bearer mfk_live_..."{ "data": { "id": "client_01J5...", "email": "dev@example.com", "name": "Avery Dev", "default_team_id": "team_01J6...", "role": "client", "plan": "developer", "scopes": ["sites:read", "deployments:write", "jobs:read"] // an API key lists its explicit set; a human session reports ["*"] }, "request_id": "req_01J9..."}PATCH /v1/account
Section titled “PATCH /v1/account”account:write Update account fields. Returns 204
on success. Display and preference fields need no password; changing your email or
password requires current_password.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | no | Display name for the account. |
default_team_id |
string | no | Must be a team you actively belong to (else 422). |
billing_cc_email |
string | no | Extra recipient for billing email. |
new_email |
string | no | New login email — requires current_password. |
new_password |
string | no | New password — requires current_password. |
current_password |
string | with the two above | Proves possession before a credential change. |
curl -X PATCH https://api.managed.dev/v1/account \ -H "Authorization: Bearer mfk_live_..." \ -H "Content-Type: application/json" \ -d '{ "new_email": "avery@acme.dev", "current_password": "..." }'A team is the unit of collaboration and billing. Roles are assigned per team, and sites can be grouped into team projects.
GET · POST /v1/teams
Section titled “GET · POST /v1/teams”- List (teams:read) the teams you belong to,
cursor-paginated. Each team reports
my_role— your role in it. - Create (teams:write) a team; you become its
owner.
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Human-readable team name. |
curl -X POST https://api.managed.dev/v1/teams \ -H "Authorization: Bearer mfk_live_..." \ -H "Idempotency-Key: 9c2f...a1" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Web" }'mf teams create --name "Acme Web"{ "data": { "team_id": "team_01J6..." }, "request_id": "req_01J9..."}GET · PATCH · DELETE /v1/teams/{teamID}
Section titled “GET · PATCH · DELETE /v1/teams/{teamID}”Retrieve (teams:read) or update
(teams:write, owner/admin only) a team. Delete
(teams:write) is owner-only and returns 204 —
the team must be empty of sites first.
GET /v1/teams/{teamID}/plan
Section titled “GET /v1/teams/{teamID}/plan”teams:read The team’s plan and live usage against
its limits — sites, environments, and storage. Use this before a create call to avoid
a quota_exceeded error.
{ "data": { "plan": "developer", "label": "Developer", "limits": { "max_sites": 5, "max_environments": 15, "max_branches_per_site": 10, "max_concurrent_jobs": 4, "max_storage_gb": 25 }, "usage": { "sites": 3, "environments": 6, "storage_gb": 11.4 } }, "request_id": "req_01J9..."}GET /v1/teams/{teamID}/sites
Section titled “GET /v1/teams/{teamID}/sites”teams:read List the sites owned by the team — a convenience filter over the sites collection.
Members & roles
Section titled “Members & roles”Members are added to a team with one of five roles. The role caps everything a member — and any key they mint — can do.
| Role | Can do |
|---|---|
owner |
Everything, including deleting the team and managing billing. |
admin |
Manage members, projects, and sites; cannot delete the team. |
site_manager |
Operate sites and environments; no member or billing management. |
observer |
Read-only access to sites, observability, and audit. |
billing |
Plan, usage, and billing only; no site access. |
GET · POST /v1/teams/{teamID}/members · PATCH · DELETE /v1/teams/{teamID}/members/{memberClientID}
Section titled “GET · POST /v1/teams/{teamID}/members · PATCH · DELETE /v1/teams/{teamID}/members/{memberClientID}”teams:read to list;
teams:write (owner/admin) to add, change a role or
expiry, or remove a member. Mutations return 204. A role you assign can never
outrank your own.
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id |
string | add only | Account id of the person to add. |
role |
string | yes | One of owner, admin, site_manager, observer, billing. |
expires_at |
string | null | no | RFC 3339 expiry for a time-boxed membership — a contractor who falls off the team automatically. On PATCH, a value sets it, null clears it, and omitting the key leaves it unchanged. |
curl -X POST https://api.managed.dev/v1/teams/team_01J6.../members \ -H "Authorization: Bearer mfk_live_..." \ -H "Content-Type: application/json" \ -d '{ "client_id": "client_01J5...", "role": "site_manager", "expires_at": "2026-09-30T23:59:59Z" }'mf teams members add team_01J6... casey@example.com \ --role site_manager --expires 2026-09-30T23:59:59ZInvites
Section titled “Invites”Invites are pending memberships for people who don’t have an account id yet.
GET /v1/teams/{teamID}/invites— teams:read list pending invites (owner/admin only).POST /v1/teams/{teamID}/invites— teams:write create an invite:role(required), optionalemailandexpires_at.DELETE /v1/teams/{teamID}/invites/{inviteID}— teams:write revoke a pending invite;204.
Projects
Section titled “Projects”Projects group sites. They come in two flavors with the same shape: personal projects under your account, and team projects under a team. See projects.
| Endpoint | Scope |
|---|---|
GET · POST /v1/projects · GET · PATCH · DELETE /v1/projects/{projectID} |
sites:read / sites:write |
GET · POST /v1/projects/{projectID}/sites · DELETE /v1/projects/{projectID}/sites/{siteID} |
sites:read / sites:write |
GET · POST /v1/teams/{teamID}/projects · GET · PATCH · DELETE /v1/teams/{teamID}/projects/{projectID} |
teams:read / teams:write |
GET · POST /v1/teams/{teamID}/projects/{projectID}/sites · DELETE …/sites/{siteID} |
teams:read / teams:write |
Creating takes { "name": "..." }; assigning a site takes { "site_id": "site_01J7..." }
(the site must belong to the same owner). Assign and remove return 204.
mf projects create --name "Client: Acme"mf projects assign proj_01J6... site_01J7...Audit logs
Section titled “Audit logs”Three audit feeds share one event shape (the team feed adds a keyset before cursor):
| Feed | Endpoint | Who can read |
|---|---|---|
| Account | GET /v1/account/audit |
audit:read — every event you were the actor of. |
| Site | GET /v1/sites/{siteID}/audit |
audit:read — events done to one site. |
| Team | GET /v1/teams/{teamID}/audit |
audit:read — owner/admin only. |
| Parameter | Type | Required | Description |
|---|---|---|---|
event |
string | no | Filter to a single event type, e.g. snapshot_restore. |
actor |
string | no | Filter to events performed by one principal. |
since / until |
string | no | RFC 3339 window — since inclusive, until exclusive. |
limit / cursor |
— | no | Pagination. |
curl "https://api.managed.dev/v1/account/audit?since=2026-06-17T00:00:00Z&limit=50" \ -H "Authorization: Bearer mfk_live_..."{ "data": [ { "id": "aud_01J9...", "event": "snapshot_restore", "outcome": "success", "actor_kind": "api_key", "actor_user_id": "client_01J5...", "actor_email": "dev@example.com", "actor_key_id": "key_01J7...", "team_id": "team_01J6...", "site_id": "site_01J7...", "meta": { "snapshot_id": "snap_01J8..." }, "created_at": "2026-06-24T13:58:10Z" } ], "pagination": { "next_cursor": "eyJ0...", "has_more": true }, "request_id": "req_01J9..."}actor_kind is member, api_key, or system; actor_user_id is the acting
principal even when the actor was an API key, and outcome records whether the action
succeeded. See the audit log concept page.