Skip to main content
A project groups an organization’s account kits and child projects (the tenant users you provision per end-user):
Use one when a single organization needs more than one scope — staging next to production, an acquired brand, one project per app you ship. If you don’t need that, you never see the layer: every organization has a default project and every call that names no project resolves to it.
Migration 059 created the default project for every existing organization and backfilled every account kit, child project, connection, vault entry and approval into it. Nothing written before projects existed changes behaviour — see Projects (architecture).

CLI first

Create a project

Response:
company_id is the deprecated spelling of the same id, returned so a caller written against the old name does not have to be rewritten.

Parameters

Work inside a project

forProject("default") declines to name a project rather than naming the default one: on an un-pinned key it resolves to the organization’s default project, and on a key pinned to another project it resolves to the pin. naive.forUser(id) is the same resolution without writing the sentinel.

Pin a key to a project

An API key can be pinned to a project at creation (active_project_id), the way it can be sealed to a subject. A pinned key can only act inside its project: a request naming a different one is a 403 key_project_mismatch, never a redirect. Leave the project off the path (or use default) to act inside the pin.

Delete a project

Refused while the project still holds account kits or child projects — deleting it would cascade into every primitive underneath — and the default project can never be deleted.

Error handling

Back-compat

Every old spelling keeps working and resolves to the default project: naive.forUser(id), naive.users, naive.accountKits, naive use <child_project_id>, /v1/users/..., /v1/company, and MCP tools called with user_id and no project_id.