Amba

Service Accounts

Scoped backend credentials and delegated operator tokens for app-factory builders.

Service accounts are the steady-state backend credential for app-factory products. A real Amba developer creates a scoped service account once, stores the returned amb_dsvc_ secret in the partner backend, and uses it to mint short-lived delegated operator tokens (amb_dop_) for builder agents.

The builder remains the partner app's user. Amba stores subject_external_type, subject_external_id, and optional subject_label for audit, but the builder does not become an Amba developer.

Endpoints

MethodPathAuthDescription
POST/v1/admin/orgs/:orgId/service-accountsDeveloper BearerCreate a scoped service account under an org subtree.
GET/v1/admin/orgs/:orgId/service-accountsDeveloper BearerList service accounts for an org. Secrets are redacted.
POST/v1/admin/service-accounts/:serviceAccountId/revokeDeveloper BearerSoft-revoke a service account.
POST/v1/admin/service-accounts/:id/tokensService account BearerMint a delegated operator token.
GET/v1/admin/service-accounts/:id/tokensService account BearerList delegated tokens minted by the service account.
POST/v1/admin/delegated-tokens/:tokenId/revokeService account or developer BearerSoft-revoke one delegated token.

Service-account Bearers are accepted only on delegated-token lifecycle routes. Delegated operator Bearers are accepted only on delegated-capable operate routes. All other admin routes reject them by default.

Service account model

FieldMeaning
organization_idOrg subtree root the service account may delegate within.
max_roleHighest role any delegated token may receive.
created_by_developer_idAudit actor that created the service account.
acting_developer_idOwnership lineage stamped onto orgs/projects created by delegated provisioning.

acting_developer_id defaults to the scoped org owner. It may be overridden only to a developer who is owner/admin on that same org.

Delegated operator token model

Delegated tokens are opaque, DB-backed, short-lived credentials:

  • scope_type: org_subtree or project
  • scope_id: the org or project UUID
  • role: owner, admin, member, or viewer
  • capabilities: non-empty subset of org:read, org:update, project:admin, provision:write
  • subject_external_type / subject_external_id: partner-owned builder identity

project:admin means full project-local admin inside the token's scope. The boundary is containment: the token cannot escape to a sibling project/org, service-account lifecycle, delegated-token lifecycle, org membership, org billing source, project ownership transfer, or other root/platform controls.

Create a service account

curl -sS -X POST "$AMBA_API_URL/v1/admin/orgs/$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. Store the amb_dsvc_ secret in the partner backend only.

Mint a delegated token

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",
    "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 amb_dop_ token is shown once.

Response shape:

{
  "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": null,
    "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"
  }
}

Use data.id as the delegated-token id for revoke/list UX. There is no token_id alias in the response.

Use a delegated token

Delegated operator tokens are Admin API Bearers:

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

The @layers/amba-node SDK is the runtime client/server-key SDK for /v1/client/*; do not configure it with an amb_dop_ token. Server-side collection reads/writes that need delegated containment should call /v1/admin/* with raw HTTP or a small admin wrapper that sends Authorization: Bearer <amb_dop_...>.

Revocation

Revocation is soft and 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.

MCP tools

MCP exposes service-account lifecycle tools for developer-authenticated setup:

  • amba_service_accounts_create
  • amba_service_accounts_list
  • amba_service_accounts_revoke

Delegated token minting is deliberately not an MCP tool. It is an HTTP backend-to-backend call made by the partner app with its amb_dsvc_ secret.

See App Factory Delegated Operators for the end-to-end Shipyard-style flow.

On this page