Self-Hosted Onboarding
Set up AGLedger from scratch: create enterprise, agents, keys, and run your first mandate.
Production deployments: For repeatable, version-controlled setup, see YAML Provisioning — declare enterprises, agents, and schemas in YAML files instead of manual API calls. This guide covers the imperative API approach, which is better for exploration and one-off setup.
Prerequisites
- AGLedger running on your infrastructure (Helm chart on Kubernetes, or Docker)
- A platform key (
ach_pla_...) — generated during initial deployment
Step 1: Create your enterprise
PLATFORM_KEY="ach_pla_your_platform_key"
API_BASE="https://agledger.your-company.com"
curl -X POST "$API_BASE/v1/admin/enterprises" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Acme Corp", "slug": "acme-corp"}'
Response:
{
"id": "019d3b11-60c4-...",
"name": "Acme Corp",
"slug": "acme-corp",
"trustLevel": "sandbox",
"nextSteps": [
{
"action": "Upgrade trust level",
"method": "PATCH",
"href": "/v1/admin/accounts/019d3b11-60c4-.../trust-level",
"description": "Upgrade from sandbox to active BEFORE creating API keys"
},
{ "action": "Create an API key", "method": "POST", "href": "/v1/admin/api-keys" },
{ "action": "Create agents", "method": "POST", "href": "/v1/admin/agents" }
]
}
The API returns nextSteps guiding you through setup. New enterprises start at sandbox trust level — keys created at sandbox level can't access most endpoints.
ENTERPRISE_ID="019d3b11-60c4-..."
Step 2: Elevate trust level
Upgrade from sandbox to active before creating API keys:
curl -X PATCH "$API_BASE/v1/admin/accounts/$ENTERPRISE_ID/trust-level" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountType": "enterprise",
"trustLevel": "active",
"reason": "Initial setup"
}'
Step 3: Create enterprise API key
curl -X POST "$API_BASE/v1/admin/api-keys" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"ownerId": "'$ENTERPRISE_ID'",
"ownerType": "enterprise",
"role": "enterprise",
"scopeProfile": "standard"
}'
Response:
{ "apiKey": "ach_ent_abc123...", "id": "...", "role": "enterprise", "scopeProfile": "standard" }
Save this key — it's your enterprise's primary credential.
Important: Always specify
scopeProfile(or explicitscopes) when creating keys. Without it, keys get restrictive defaults that may cause 403 errors on operations like schema registration. Use"standard"for enterprise keys and"agent-full"for agent keys to start with full access, then narrow later if needed.
Step 4: Create agents and keys
Create a principal agent (assigns work) and a performer agent (does work):
# Create principal agent
curl -X POST "$API_BASE/v1/admin/agents" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Procurement Orchestrator",
"agentClass": "system",
"ownerRef": "platform-team@acme.com",
"orgUnit": "procurement",
"description": "Orchestrates procurement mandates on behalf of the enterprise"
}'
# → { "id": "019d3b11-6154-...", "trustLevel": "sandbox", "agentClass": "system" }
PRINCIPAL_ID="019d3b11-6154-..."
# Create performer agent
curl -X POST "$API_BASE/v1/admin/agents" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sourcing Agent",
"agentClass": "system",
"ownerRef": "platform-team@acme.com",
"orgUnit": "procurement"
}'
# → { "id": "019d3b11-6181-...", "agentClass": "system" }
PERFORMER_ID="019d3b11-6181-..."
Agent identity fields (all optional, all settable at creation or via PATCH /v1/agents/:id):
| Field | Description | Example |
|-------|-------------|---------|
| agentClass | personal, system, team, or ephemeral (default: system) | "system" |
| ownerRef | Email or identity URI of the responsible person/team | "platform-team@acme.com" |
| orgUnit | Department, team, or cost center | "procurement" |
| description | Plain-text description of what this agent does (max 2000 chars) | "Orchestrates procurement mandates" |
These fields appear in audit trails and /auth/me responses, making it easier to trace which team owns which agent in production.
Elevate both to active and create their API keys:
# Elevate agents
for AGENT_ID in $PRINCIPAL_ID $PERFORMER_ID; do
curl -X PATCH "$API_BASE/v1/admin/accounts/$AGENT_ID/trust-level" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{ "accountType": "agent", "trustLevel": "active", "reason": "Initial setup" }'
done
# Create agent API keys
curl -X POST "$API_BASE/v1/admin/api-keys" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"ownerId": "'$PRINCIPAL_ID'",
"ownerType": "agent",
"role": "agent",
"scopeProfile": "agent-full"
}'
# → { "apiKey": "ach_age_principal_...", "scopeProfile": "agent-full" }
curl -X POST "$API_BASE/v1/admin/api-keys" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"ownerId": "'$PERFORMER_ID'",
"ownerType": "agent",
"role": "agent",
"scopeProfile": "agent-full"
}'
# → { "apiKey": "ach_age_performer_...", "scopeProfile": "agent-full" }
Scope profiles for agent keys:
agent-fullgrants 8 scopes including mandates, receipts, disputes, and events. For agents that should only read data, useagent-readonly. Discover all profiles viaGET /v1/admin/scope-profiles. See YAML Provisioning for the full profile table.
Approve agents for the enterprise:
curl -X PUT "$API_BASE/v1/enterprises/$ENTERPRISE_ID/agents/$PRINCIPAL_ID" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" -d '{}'
curl -X PUT "$API_BASE/v1/enterprises/$ENTERPRISE_ID/agents/$PERFORMER_ID" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" -d '{}'
Step 4b: Configure enforcement (optional)
Set enterprise-wide verification behavior:
curl -X PATCH "$API_BASE/v1/admin/enterprises/$ENTERPRISE_ID/config" \
-H "Authorization: Bearer $PLATFORM_KEY" \
-H "Content-Type: application/json" \
-d '{
"enforcement": {
"toleranceEnforcement": "enforced",
"deadlineEnforcement": "advisory",
"schemaValidation": "advisory"
}
}'
Enforcement modes:
enforced— violations fail verificationadvisory— violations logged but don't failnone— no checking
Step 5: Your first mandate
Now use the agent keys to run a real workflow:
PRINCIPAL_KEY="ach_age_principal_..."
PERFORMER_KEY="ach_age_performer_..."
# Principal creates mandate
curl -X POST "$API_BASE/v1/mandates/agent" \
-H "Authorization: Bearer $PRINCIPAL_KEY" \
-H "Content-Type: application/json" \
-d '{
"principalAgentId": "'$PRINCIPAL_ID'",
"performerAgentId": "'$PERFORMER_ID'",
"contractType": "ACH-PROC-v1",
"contractVersion": "1",
"platform": "first-mandate",
"criteria": {
"item_description": "Office supplies for new team",
"quantity": { "target": 10, "tolerance_pct": 10, "unit": "units" },
"price_ceiling": { "amount": 500, "currency": "USD" }
},
"tolerance": { "quantityPct": 10, "priceMargin": 50, "graceSeconds": 3600 }
}'
# → { "id": "019d3b11-aa52-...", "status": "PROPOSED" }
MANDATE_ID="019d3b11-aa52-..."
# Performer accepts
curl -X POST "$API_BASE/v1/mandates/$MANDATE_ID/accept" \
-H "Authorization: Bearer $PERFORMER_KEY" \
-H "Content-Type: application/json" -d '{}'
# Principal activates
curl -X POST "$API_BASE/v1/mandates/$MANDATE_ID/transition" \
-H "Authorization: Bearer $PRINCIPAL_KEY" \
-H "Content-Type: application/json" \
-d '{ "action": "activate" }'
# Performer submits receipt
curl -X POST "$API_BASE/v1/mandates/$MANDATE_ID/receipts" \
-H "Authorization: Bearer $PERFORMER_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "'$PERFORMER_ID'",
"evidence": {
"item_description": "Office supplies",
"quantity": 10,
"total_cost": { "amount": 450, "currency": "USD" },
"supplier": { "id": "SUP-001", "name": "Office Depot" },
"confirmation_ref": "PO-FIRST-001"
}
}'
# Check status (should be FULFILLED within seconds)
curl "$API_BASE/v1/mandates/$MANDATE_ID" \
-H "Authorization: Bearer $PRINCIPAL_KEY"
# → { "status": "FULFILLED", ... }
Step 6: Verify it worked
ENTERPRISE_KEY="ach_ent_abc123..."
# Audit trail — every state transition recorded
curl "$API_BASE/v1/mandates/$MANDATE_ID/audit" \
-H "Authorization: Bearer $ENTERPRISE_KEY"
# Identity check — who is this key?
curl "$API_BASE/v1/auth/me" \
-H "Authorization: Bearer $ENTERPRISE_KEY"
# → { "ownerId": "019d3b11-60c4-...", "role": "enterprise", "trustLevel": "active" }
curl "$API_BASE/v1/auth/me" \
-H "Authorization: Bearer $PRINCIPAL_KEY"
# → { "ownerId": "019d3b11-6154-...", "role": "agent", "trustLevel": "active" }
The setup sequence
1. POST /admin/enterprises → create enterprise (sandbox)
2. PATCH /admin/accounts/:id/trust → elevate to active
3. POST /admin/api-keys → enterprise key (scopeProfile: standard)
4. POST /admin/agents → create agents (with identity fields)
5. PATCH /admin/accounts/:id/trust → elevate agents to active
6. POST /admin/api-keys → agent keys (scopeProfile: agent-full)
7. PUT /enterprises/:id/agents/:id → approve agents
8. PATCH /admin/enterprises/:id/config → set enforcement (optional)
9. POST /mandates/agent → first mandate
Total: 8-9 API calls from zero to first mandate.
Next: Onboard your agents
Your enterprise is set up and your first mandate works. If your AI agents will create mandates or submit receipts, pre-built agent skill instructions can teach agents the right contract types and field formats — reducing token cost by 17-47% and eliminating schema discovery errors.
Related guides
- Installation — Docker Compose, Kubernetes/Helm, air-gap bundles, and production hardening
- Operations — Upgrades, backup/restore, rollback, secret rotation, observability, and HA
- Configuration Reference — All environment variables, licensing, database compatibility, and deployment modes
- TLS Configuration — Database TLS and ingress TLS (ACM, cert-manager, reverse proxies)
- Version Matrix — Supported versions and upstream EOL dates
- Vault & Signing Keys — Key rotation, offline verification, and disaster recovery
- Scope Profiles — Least-privilege API key profiles
Validated end-to-end against API v0.19.17 on 2026-04-20:
- Onboarding lifecycle (24 assertions)
- Scope profiles and identity