Scope Profiles
Control what each API key can do. Scope profiles apply the principle of least privilege to AGLedger API keys — every key gets only the access it needs.
Why Scope Profiles Exist
Every AGLedger API key is assigned a scope profile at creation. The profile determines which endpoints the key can call. Without scope profiles, every enterprise key would have full operational access — fine for development, risky for production.
Scope profiles solve three problems:
- Least privilege. A dashboard key can read metrics but cannot create mandates. A sidecar key can submit receipts but cannot manage webhooks.
- Audit clarity. When every key has a named profile, you know exactly what any key in your system is authorized to do.
- Safe defaults. New enterprise keys default to the
standardprofile (19 scopes). New agent keys default toagent-full(8 scopes). Both may grant more access than a specific integration needs.
Listing Available Profiles
Discover all scope profiles and their contents:
curl "$API_BASE/v1/admin/scope-profiles" \
-H "Authorization: Bearer $PLATFORM_KEY"
Response:
{
"data": [
{
"name": "standard",
"description": "Core lifecycle: mandates, receipts, schemas, webhooks",
"allowedRoles": ["enterprise"],
"scopes": ["mandates:read", "mandates:write", "receipts:read", "receipts:write", "..."]
},
{
"name": "agent-full",
"description": "All agent scopes including disputes, compliance, agents:read",
"allowedRoles": ["agent"],
"scopes": ["mandates:read", "mandates:write", "receipts:read", "receipts:write", "..."]
}
]
}
Each profile includes:
| Field | Description |
|-------|-------------|
| name | Profile identifier. Use this as the scopeProfile value when creating or updating keys. |
| description | What the profile is designed for. |
| allowedRoles | Which key roles can use this profile (enterprise, agent). |
| scopes | The exact scopes this profile grants. |
Auth: Platform key required (ach_pla_*).
Profile Reference
AGLedger ships 9 built-in scope profiles. Eight are discoverable via the API. The ninth (platform) grants unrestricted access and is not listed.
Enterprise Profiles
| Profile | Scopes | Use Case |
|---------|--------|----------|
| standard | 19 | Default for enterprise keys. Full operational access: mandates, receipts, schemas, webhooks, agents, disputes. Appropriate for backend services that manage the full mandate lifecycle. |
| dashboard | read-only | Dashboard and reporting UI. Includes dashboard:read, audit:read, events:read, disputes:read, reputation:read, plus read access to mandates and schemas. Cannot create or modify resources. |
| iac-pipeline | config mgmt | CI/CD and infrastructure automation. Includes agents:manage, webhooks:manage, admin:keys, schemas:write. Cannot create mandates or submit receipts. |
| schema-manager | schema ops | Schema registry management. For teams that own contract type definitions but should not interact with mandates. |
| restrictive | 6 | Least-privilege baseline: mandates:read, mandates:write, receipts:read, receipts:write, schemas:read, webhooks:read. No admin, no disputes, no dashboard. Use this when an integration only creates mandates and submits receipts. |
| sidecar | 5 | Governance sidecar proxy. Minimal scopes: mandates:read, mandates:write, receipts:write, webhooks:manage, webhooks:read. |
Agent Profiles
| Profile | Scopes | Use Case |
|---------|--------|----------|
| agent-full | 8 | Default for agent keys. Includes mandate and receipt read/write, plus agents:read, disputes:read, events:read, and compliance:read. |
| agent-readonly | read-only | Read-only agent access. For monitoring agents that observe mandates but do not perform work. |
Platform Keys
Platform keys (ach_pla_*) have unrestricted access to all endpoints. They are not assigned a scope profile and are automatically exempt from rate limits. Use platform keys only for administration — never embed them in application code.
Creating Keys with a Specific Profile
Enterprise Key with a Named Profile
curl -X POST "$API_BASE/v1/admin/api-keys" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "enterprise",
"ownerId": "ENTERPRISE_UUID",
"ownerType": "enterprise",
"label": "dashboard-readonly",
"scopeProfile": "dashboard"
}'
Response (201):
{
"id": "key-uuid",
"apiKey": "ach_ent_abc123...",
"role": "enterprise",
"scopes": ["dashboard:read", "audit:read", "events:read", "disputes:read", "reputation:read", "mandates:read", "schemas:read"],
"scopeProfile": "dashboard",
"isActive": true
}
Agent Key with a Named Profile
curl -X POST "$API_BASE/v1/admin/api-keys" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "agent",
"ownerId": "AGENT_UUID",
"ownerType": "agent",
"label": "readonly-monitor",
"scopeProfile": "agent-readonly"
}'
Enterprise Key with Explicit Scopes
If none of the built-in profiles match your needs, specify scopes directly:
curl -X POST "$API_BASE/v1/admin/api-keys" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "enterprise",
"ownerId": "ENTERPRISE_UUID",
"ownerType": "enterprise",
"label": "mandate-writer",
"scopes": ["mandates:read", "mandates:write", "schemas:read"]
}'
Use scopeProfile or scopes, not both. If both are provided, scopeProfile takes precedence.
Default behavior: If neither scopeProfile nor scopes is provided, the key receives the default profile for its role — standard for enterprise keys (19 scopes), agent-full for agent keys (8 scopes). This may grant more access than intended. Specify a profile explicitly in production.
Auth: Platform key required for key creation.
Checking a Key's Current Scopes
Any key can inspect its own scopes via the introspection endpoint:
curl "$API_BASE/v1/auth/me" \
-H "Authorization: Bearer $YOUR_KEY"
Response:
{
"apiKeyId": "key-uuid",
"role": "enterprise",
"ownerId": "enterprise-uuid",
"ownerType": "enterprise",
"trustLevel": "active",
"scopes": ["mandates:read", "mandates:write", "schemas:read"],
"expiresAt": null,
"allowedIps": null
}
The scopes array always reflects the key's current effective permissions. Use this endpoint to verify what a key can do after creation or after a scope change.
Elevating and De-Elevating Scopes
Change a key's scopes at any time using the admin PATCH endpoint. Changes take effect immediately — no restart or cache flush required.
Elevate: Add Scopes
Grant schemas:write to an existing key:
curl -X PATCH "$API_BASE/v1/admin/api-keys/$KEY_ID" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"scopes": ["mandates:read", "schemas:read", "schemas:write"]
}'
Response (200):
{
"id": "key-uuid",
"isActive": true,
"scopes": ["mandates:read", "schemas:read", "schemas:write"],
"scopeProfile": null
}
De-Elevate: Remove Scopes
Remove schemas:write from the same key:
curl -X PATCH "$API_BASE/v1/admin/api-keys/$KEY_ID" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"scopes": ["mandates:read", "schemas:read"]
}'
The key is immediately denied access to endpoints requiring schemas:write.
Switch to a Named Profile
Replace a key's scopes with a named profile:
curl -X PATCH "$API_BASE/v1/admin/api-keys/$KEY_ID" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"scopeProfile": "dashboard"
}'
Rules
- Platform key required. Only platform keys (
ach_pla_*) can PATCH scopes. Enterprise and agent keys receive 403. - No self-elevation. A key cannot PATCH its own scopes, even if it has admin access.
- Role constraints enforced. Agent profiles cannot be applied to enterprise keys, and vice versa. Attempting a cross-role profile assignment returns 400.
- Invalid scope names rejected. Unknown scope strings return 400.
- Immediate effect. Scope changes are reflected in the next request. The
/auth/meendpoint shows updated scopes immediately.
Scope Enforcement
When a key lacks the required scope for an endpoint, AGLedger returns a 403 with a descriptive error:
{
"type": "/problems/forbidden",
"status": 403,
"error": "INSUFFICIENT_SCOPE",
"detail": "This action requires scope 'dashboard:read'. Your key has 5 scopes — call GET /auth/me to see them."
}
The detail field names the specific scope needed and points to /auth/me for introspection. Use this to diagnose access issues without guessing.
YAML Provisioning Integration
When using YAML provisioning, assign scope profiles directly in your config files:
enterprises:
- name: Acme Corp
slug: acme-corp
apiKeys:
- label: dashboard
scopeProfile: dashboard
- label: ci-pipeline
scopeProfile: iac-pipeline
agents:
- slug: procurement-bot
displayName: Procurement Bot
apiKeys:
- label: primary
scopeProfile: agent-full
Use scopeProfile or scopes (not both) in YAML, same as the API. See the YAML Provisioning guide for the full configuration reference.
Note: Changing the scope profile on an existing provisioned key in YAML has no effect — keys are created once and skipped on subsequent runs. To change scopes on an existing key, use PATCH /v1/admin/api-keys/:keyId.
Best Practices
Start restrictive, elevate as needed. Create keys with restrictive or sidecar and add scopes when the integration requires them. This is safer than starting with standard and discovering a leaked key has full access.
One key per integration. Give each service, agent, or pipeline its own key with a descriptive label. When you need to revoke access, you deactivate one key without disrupting others.
Audit default keys. New enterprise keys default to standard (19 scopes). If your key was created without an explicit profile, check /auth/me to see what it can do, then consider de-elevating to a narrower profile.
Use profiles over explicit scopes. Named profiles are easier to audit and communicate. Use explicit scopes arrays only when no built-in profile matches your requirements.
Dashboard keys for read-only access. The dashboard profile is designed for UI integrations and reporting tools. It grants read access to mandates, schemas, audit trails, disputes, events, and reputation — but cannot modify anything.
IaC-pipeline keys for automation. CI/CD pipelines that manage agents, webhooks, and schemas but never create mandates should use iac-pipeline. This keeps operational and configuration concerns separated.
| Integration | Recommended Profile |
|-------------|-------------------|
| Backend service (full lifecycle) | standard |
| Dashboard / reporting UI | dashboard |
| CI/CD pipeline | iac-pipeline |
| Governance sidecar | sidecar |
| Schema management tool | schema-manager |
| Receipt-only integration | restrictive |
| AI agent (full) | agent-full |
| AI agent (monitoring) | agent-readonly |
Validated: 179 assertions across scope profile discovery, enforcement, elevation, de-elevation, and backward compatibility. View test source.