Amba

App Factory Delegated Operators

Build app-factory products where your users operate their own Amba projects without ever receiving your root PAT.

App factories create apps on behalf of their own users. A Shipyard-style product has one platform root organization, one child organization per customer app or agency account, and projects under those customer organizations.

The secure steady-state credential is not a developer PAT. Use a scoped service account to mint short-lived delegated operator tokens:

Shipyard root org
├─ customer org A  -> projects
└─ customer org B  -> projects

The Shipyard backend stores one amb_dsvc_ service-account secret scoped to the root org. When a builder opens an agent session, Shipyard verifies that builder's membership in its own app, then asks Amba to mint an amb_dop_ token scoped to that builder's customer org or project.

The builder agent only sees amb_dop_. Amba enforces the token's scope and capabilities on every request.

Model

  • Developer PAT: used by a real Amba developer to create or revoke service accounts. Do not use it as the partner backend's steady-state credential.
  • Service account (amb_dsvc_): long-lived backend credential, scoped to one org subtree, capped by max_role, and soft-revocable.
  • Delegated operator token (amb_dop_): short-lived builder credential, minted by a service account for one external subject and one scope.
  • Builder identity: remains your app user. Amba stores subject_external_type and subject_external_id for audit, but does not make the builder an Amba developer.

project:admin means full project-local admin within the token's scope. A builder who owns an app should be able to manage that app's Amba features: collections, content, users, social graph, functions, secrets, sites, payments, and other project-local surfaces.

The boundary is containment. The same token cannot reach a sibling project, the platform root's controls, service-account lifecycle, delegated-token lifecycle, project billing rollup, project ownership transfer, org membership, or org payment source.

Create a service account

Use a developer PAT once to create the service account under the app-factory root org:

curl -sS -X POST "$AMBA_API_URL/v1/admin/orgs/$ROOT_ORG_ID/service-accounts" \
  -H "Authorization: Bearer $AMBA_DEV_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "shipyard-backend",
    "max_role": "admin"
  }'

The response returns data.secret once:

{
  "data": {
    "id": "8c5b...",
    "secret": "amb_dsvc_...",
    "max_role": "admin",
    "acting_developer_id": "..."
  }
}

Store that secret in the partner backend. Do not expose it to builders or agents.

acting_developer_id is the ownership lineage Amba stamps onto orgs/projects created by delegated provisioning. By default it is the scoped org owner. You can override it only to a developer who is owner/admin on the service account's root org.

Mint a builder token

After your backend verifies that a builder belongs to customer org A, mint a short-lived token scoped to that org:

curl -sS -X POST "$AMBA_API_URL/v1/admin/service-accounts/$SA_ID/tokens" \
  -H "Authorization: Bearer $AMBA_SERVICE_ACCOUNT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "subject_external_type": "shipyard_builder",
    "subject_external_id": "builder_123",
    "subject_label": "ava@example.com",
    "scope_type": "org_subtree",
    "scope_id": "CUSTOMER_ORG_ID",
    "role": "admin",
    "capabilities": ["project:admin", "org:read", "org:update", "provision:write"],
    "expires_in_seconds": 3600
  }'

Return only data.token to the builder agent. The plaintext token is shown once.

The mint response is a standard Amba envelope. The delegated-token id is data.id:

{
  "data": {
    "id": "0f6a1c3e-7b9d-4f4b-8a8f-2b5a9f3f0c11",
    "token": "amb_dop_...",
    "token_prefix": "amb_dop_...",
    "token_last_4": "Ab12",
    "service_account_id": "8c5b...",
    "subject_external_type": "shipyard_builder",
    "subject_external_id": "builder_123",
    "subject_label": "ava@example.com",
    "scope_type": "org_subtree",
    "scope_id": "CUSTOMER_ORG_ID",
    "role": "admin",
    "capabilities": ["project:admin", "org:read", "org:update", "provision:write"],
    "expires_at": "2026-06-20T20:10:00.000Z",
    "created_at": "2026-06-20T19:10:00.000Z"
  }
}

Operate with the delegated token

The builder agent calls normal admin endpoints with the delegated token:

curl -sS "$AMBA_API_URL/v1/admin/projects/$PROJECT_ID" \
  -H "Authorization: Bearer $AMBA_DELEGATED_OPERATOR_TOKEN"

In-scope project-local routes work. Out-of-scope resources return 404 so sibling org/project existence is not leaked. In-scope requests missing a required capability return 403.

Use the Admin API for these calls. The @layers/amba-node SDK is the runtime client/server-key SDK for /v1/client/*; it is not the delegated-operator admin client. For backend workers and agents, call /v1/admin/* with raw HTTP (or a small wrapper) and Authorization: Bearer <amb_dop_...>.

Delegated provisioning is parent-billed only:

curl -sS -X POST "$AMBA_API_URL/v1/admin/provision" \
  -H "Authorization: Bearer $AMBA_DELEGATED_OPERATOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "parent_org_id": "CUSTOMER_ORG_ID",
    "external_ref": "app_456",
    "project_name": "Dream Journal"
  }'

If a delegated caller asks for payment_source: "self" or billing_mode: "self", Amba returns 403. Direct billing changes remain a developer-authenticated operation.

Revoke

Revoke a token with the issuing service account:

curl -sS -X POST "$AMBA_API_URL/v1/admin/delegated-tokens/$TOKEN_ID/revoke" \
  -H "Authorization: Bearer $AMBA_SERVICE_ACCOUNT_SECRET"

Revoke the service account with a developer PAT:

curl -sS -X POST "$AMBA_API_URL/v1/admin/service-accounts/$SA_ID/revoke" \
  -H "Authorization: Bearer $AMBA_DEV_PAT"

Revocation is bounded by the auth cache TTL, currently up to 30 seconds per API instance. Delegated tokens should still be short-lived; use one hour by default and keep the maximum at 24 hours.

Smoke test

The repository includes a customer-shoes smoke for this flow:

AMBA_API_URL=https://api.staging.amba.dev \
AMBA_DEV_PAT=amb_dpat_... \
bash e2e/delegated-operator-smoke.sh

Run it against staging before shipping changes to the delegated operator surface.

On this page