Organizations
Parent→child organizations as the ownership + payment boundary, plus the idempotent app-factory provisioning call.
An organization is the ownership and payment boundary that sits above projects. Every developer gets a personal org at signup; teams and app factories create additional orgs and nest them. Ownership is the authoritative boundary — a member of a parent org manages every descendant org and project — while developer_id is retained on each project as creator/contact.
Billing stays per project (tier, usage, the project's own subscription are unchanged). The org is only the payment entity: it holds the Stripe customer Amba charges and the Connect account Amba pays. A per-org payment_source toggle — 'self' (the org uses its own card) or 'parent' (defer up the tree to the nearest self-paying ancestor) — is the "bill the parent agency vs. bill the child directly" switch.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v1/admin/orgs | Create an org (optionally under a parent_org_id). |
| GET | /v1/admin/orgs | List orgs you own or manage, plus their descendants. |
| GET | /v1/admin/orgs/:orgId | Get one org + your effective role. |
| PATCH | /v1/admin/orgs/:orgId | Update name / slug / payment_source. |
| DELETE | /v1/admin/orgs/:orgId | Delete an empty org (409 ORG_NOT_EMPTY otherwise). |
| GET | /v1/admin/orgs/:orgId/members | List members (owner/admin only — emails are PII). |
| POST | /v1/admin/orgs/:orgId/invites | Invite a developer by email (owner/admin). |
| POST | /v1/admin/orgs/:orgId/transfer-ownership | Transfer ownership (owner only). |
| POST | /v1/admin/orgs/:orgId/detach | Detach a child org to a root (graduation; owner only). |
| POST | /v1/admin/provision | Idempotent app-factory: org + project + keys in one call. |
| GET | /v1/admin/projects/:projectId/provisioning-status | Poll provisioning state for a freshly-created project. |
Org-invite acceptance is a separate router mounted at /v1/admin/org-invites (the acceptor doesn't know the org until they accept).
Access model
authorizedForOrg / authorizedForProject resolve the caller's effective role by walking the org tree upward (depth-bounded) and taking the strongest grant across: the retained project creator, the owner of the project's org or any ancestor, organization_members on the org or an ancestor, and per-project project_members. A parent-org manager therefore manages all descendants; a child member never gains access upward or sideways. Mutations and PII reads require manage-level (owner or admin).
POST /v1/admin/orgs
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name. |
parent_org_id | string | no | Nest under a parent (you must manage the parent). Omit for a root. |
slug | string | no | Unique slug when set. |
payment_source | string | no | 'self' (default) or 'parent'. |
POST /v1/admin/provision (app factory)
One idempotent call that provisions a child org + project and returns its keys — built for an app factory standing up hundreds of generated apps under one root-org PAT.
| Field | Type | Required | Description |
|---|---|---|---|
parent_org_id | string | yes | The root/agency org to provision under (you must manage it). |
external_ref | string | yes | Your stable id for this customer/app. The idempotency anchor. |
org_name | string | yes | Name for the child org. |
project_name | string | no | Name for the project (defaults from org_name). |
bundle_id | string | no | App bundle id passed through to provisioning. |
One-time-key contract. The first call returns plaintext api_keys (client + server) and idempotent: false. A retry with the same (parent_org_id, external_ref) returns the same org/project ids, idempotent: true, keys_already_issued: true, and no plaintext — keys are sha256-hashed and unrecoverable. Lost keys are re-issued via the project's api-keys endpoint. Concurrent double-POSTs collapse to a single org/project (FOR UPDATE on the parent). The same external_ref under two different parents yields two orgs.
After a fresh insert, provisioning runs asynchronously; poll GET /v1/admin/projects/:projectId/provisioning-status until active.
Graduation (agency → direct)
A child that outgrows the factory graduates without moving any project or database:
POST .../transfer-ownership— hand the org to the customer's developer (optionally removing the previous owner).PATCH .../:orgIdwithpayment_source: 'self'— the org now bills its own card.POST .../detach— promote the child to a root (refused whilepayment_source = 'parent').
MCP tools
amba_orgs_create, amba_orgs_list, amba_orgs_get, amba_orgs_update, amba_orgs_invite_member, amba_orgs_transfer_owner, and the dedicated amba_provision_app for the app-factory call.