Skip to main content
A seat is an identity on a project: a human or an agent. Seats are counted by distinct identity across all of the owner’s projects, plus the owner, and capped by the plan (limits.max_seats on Tier status). Minting seats requires the Team plan.

List members

Keys are never returned here.

Mint an agent seat

An agent seat is an identity of its own, with its own pb_ key and its own line in the changelog, so an agent’s writes are attributable and revocable without touching a human’s key.
  • apiKey is returned once. There is no retrieval. The single-project form returns the same shape without projects.
  • Prefer projectIds when one agent works across several of your projects: one key to store, rotate and audit, and one seat however many projects it spans. Pass the projectId you mean on each request as usual.
  • You must own every project you name. Otherwise 403 { "error": "not_owner", "message": "You do not own: ..." } and nothing is created.
  • Adding a project later means POSTing the full list again, which mints a new identity and key. Name every project up front.
  • On Builder you get the owner seat plus your own key from the app. Provision your agent with that. Asking for a seat anyway returns 403 { "error": "team_tier_required", "message": "Adding members requires the Team tier." }.
  • At the seat cap: 403 { "error": "seat_limit", "message": "Your plan allows 5 seats. Remove a member or upgrade." }.
The agent’s key works on every endpoint. On /mutate and /workflow it rides the owner’s Team plan and the owner’s node limit.

Read-only seats

A seat can be read-only: it reads the project but cannot change or delete anything in it. Use it for an agent that reports on the plan, answers questions about it or reviews it, where a stray write would be a mistake. Pass role when you mint the seat: "editor" (the default) or "viewer".
  • A read-only seat can read everything (/nodes, /tree, /search, /iterations, /changelog, /export-okf and the rest), send view commands, post feedback and remove itself.
  • Every write is refused with 403 read_only_seat and changes nothing: every /mutate action, /workflow, and /share (a share link would outlive the seat). Owner-only calls refuse it as they refuse any member.
  • GET /api/v1/members returns each seat’s role, and GET /api/v1/projects returns seatRole, so an agent can check before it tries to write.
  • In the app, tick Read only under “Add an agent seat” in Team members. Over MCP, use add_agent_seat with role: "viewer" or set_seat_role.
  • Read-only is for agent seats. People are added as editors: role: "viewer" on an email invite returns 400 role_agents_only.

Add an existing user

The email must belong to an existing ProductBrain account (404 { "error": "user_not_found", ... } otherwise). Already a member: 400.

Invite a guest contributor

A contributor is a new, passwordless guest identity scoped to the projects you name. They work in the app UI on those projects only; AI use is billed to your plan.
One seat regardless of project count. An email that already has a ProductBrain account returns 409 { "error": "email_in_use", ... }; add that person as a full member instead. If the invitation email cannot be sent, 502 { "error": "invite_failed", ... }.

Remove a seat

The owner can remove anyone; a member can remove only themselves (403 otherwise). Not a member: 404. Removing an agent seat from one project leaves its key working on the rest. Removing its last membership revokes the key.