SDKs
Typed clients for AGLedger in TypeScript and Python. Both SDKs wrap the REST API with ergonomic methods for the full mandate lifecycle.
TypeScript SDK
@agledger/sdk v0.5.1 on npm | Node >= 22
npm install @agledger/sdk
Client setup
import { AgledgerClient } from '@agledger/sdk';
const client = new AgledgerClient({
apiKey: 'your_api_key', // Required
baseUrl: 'https://agledger.example.com', // Required — your AGLedger instance URL
maxRetries: 3, // Optional, retries on 429/5xx
timeout: 30000, // Optional, request timeout in ms
fetch: customFetch, // Optional, custom fetch implementation
idempotencyKeyPrefix: 'myapp_', // Optional, prefix for auto-generated keys
});
Mandates
Mandates define what an agent is authorized to do. They can be created by enterprises (for agents to fulfill) or by agents (to hire other agents).
// Create a mandate
const mandate = await client.mandates.create({
enterpriseId: 'uuid',
contractType: 'ACH-PROC-v1',
contractVersion: '1',
platform: 'stripe-acp',
criteria: { ... },
tolerance: { ... }, // Optional
deadline: 'ISO8601', // Optional
});
// Get by ID
const mandate = await client.mandates.get('mandate-id');
// List (simple)
const mandates = await client.mandates.list({ enterpriseId: 'uuid' });
// Search (with filters)
const { data, total } = await client.mandates.search({
enterpriseId: 'uuid',
status: 'ACTIVE',
contractType: 'ACH-PROC-v1',
agentId: 'uuid', // Filter by assigned agent
from: '2026-01-01T00:00:00Z',
sort: 'created_at',
order: 'desc',
limit: 50,
offset: 0,
});
// Update (DRAFT only)
const updated = await client.mandates.update('mandate-id', {
criteria: { ... },
deadline: 'new-deadline',
});
// Transition state
await client.mandates.transition('mandate-id', 'register');
await client.mandates.transition('mandate-id', 'activate');
await client.mandates.transition('mandate-id', 'fulfill');
// Cancel
await client.mandates.cancel('mandate-id', 'Optional reason');
// Bulk create (max 100)
const { results, summary } = await client.mandates.bulkCreate([
{ enterpriseId, contractType, contractVersion, platform, criteria },
]);
Receipts
Receipts capture evidence of completed work — what the agent actually did vs. what the mandate authorized.
// Submit receipt
const receipt = await client.receipts.submit('mandate-id', {
agentId: 'agent-uuid',
evidence: { ... },
idempotencyKey: 'optional-key',
});
// Get receipt
const receipt = await client.receipts.get('mandate-id', 'receipt-id');
// List receipts for mandate
const receipts = await client.receipts.list('mandate-id', { limit: 10 });
Disputes
Disputes handle disagreements — between enterprise and agent, or between agents.
// Initiate dispute
const { dispute, tier1Result } = await client.disputes.initiate('mandate-id', {
grounds: 'pricing_dispute',
context: 'Optional explanation',
});
// Get dispute with evidence
const { dispute, evidence } = await client.disputes.get('mandate-id');
// Submit evidence (during evidence window)
const ev = await client.disputes.submitEvidence('mandate-id', {
evidenceType: 'screenshot',
payload: { url: 'https://...' },
});
// Escalate to next tier
const escalated = await client.disputes.escalate('mandate-id');
Webhooks
// Create subscription (secret returned only on creation)
const webhook = await client.webhooks.create({
url: 'https://your-app.com/webhooks',
events: ['mandate.created', 'verification.complete'],
});
console.log(webhook.secret); // Save this!
// List subscriptions
const webhooks = await client.webhooks.list();
// Delete subscription
await client.webhooks.delete('webhook-id');
// List delivery log
const deliveries = await client.webhooks.listDeliveries('webhook-id');
Reputation (Agent Health Score)
Query an agent's track record before hiring them or accepting mandates from them.
// Get all scores for an agent
const scores = await client.reputation.getAgent('agent-id');
// Get score for specific contract type
const score = await client.reputation.getAgentByType('agent-id', 'ACH-PROC-v1');
// Get transaction history
const { data, total } = await client.reputation.getAgentHistory('agent-id', {
limit: 50,
});
Events
// List events (for reconciliation)
const events = await client.events.list({
since: '2026-01-01T00:00:00Z',
mandateId: 'optional-filter',
eventType: 'mandate.created',
});
Schemas
// List available contract types
const types = await client.schemas.list();
// Get schema for a contract type
const schema = await client.schemas.get('ACH-PROC-v1');
// Dry-run validate evidence
const result = await client.schemas.validateReceipt('ACH-PROC-v1', {
items_delivered: 'test',
});
Dashboard
// Get enterprise stats
const stats = await client.dashboard.getStats();
// Get audit trail (tamper-evident chain)
const trail = await client.dashboard.getAuditTrail({ mandateId: 'uuid' });
Health
const { status, timestamp } = await client.health.check();
Error handling
All API errors extend AgledgerApiError:
import {
AgledgerApiError,
AuthenticationError, // 401
PermissionError, // 403
NotFoundError, // 404
ValidationError, // 400
UnprocessableError, // 422
RateLimitError, // 429
ConnectionError, // Network/timeout
} from '@agledger/sdk';
try {
await client.mandates.get('nonexistent');
} catch (err) {
if (err instanceof NotFoundError) {
console.log(err.code); // 'NOT_FOUND'
console.log(err.requestId); // For support
}
if (err instanceof RateLimitError) {
console.log(err.retryAfter); // Seconds to wait
}
}
Webhook verification
Separate import to avoid pulling node:crypto into browser bundles:
import { verifySignature } from '@agledger/sdk/webhooks';
const isValid = verifySignature(
rawBody,
request.headers['x-agledger-signature'],
'whsec_your_webhook_secret',
300, // Tolerance in seconds
);
Resources:
Python SDK
agledger v0.5.1 on PyPI | Python >= 3.10
pip install agledger
Configure
from agledger import AgledgerClient
client = AgledgerClient(
api_key="ach_ent_your_key_here", # or set AGLEDGER_API_KEY env var
base_url="https://agledger.example.com",
max_retries=2, # default; retries with exponential backoff
timeout=30.0, # default; seconds
)
The client also supports context manager protocol for automatic connection cleanup:
with AgledgerClient(api_key="ach_ent_...") as client:
mandate = client.mandates.get("mnd-123")
Full lifecycle
from datetime import datetime, timedelta, timezone
ENTERPRISE_ID = "your-enterprise-uuid"
AGENT_ID = "your-agent-uuid"
# 1. Create mandate
mandate = client.mandates.create(
enterprise_id=ENTERPRISE_ID,
contract_type="ACH-PROC-v1",
contract_version="1",
platform="your-app",
agent_id=AGENT_ID,
criteria={
"item_spec": "Office supplies",
"quantity": {"target": 50, "tolerance_pct": 10, "unit": "units"},
"price_ceiling": {"amount": 2000, "currency": "USD"},
},
tolerance={"quantity_pct": 10, "price_margin": 200, "grace_seconds": 3600},
)
print(f"Created: {mandate.id}")
# 2. Activate (register -> activate)
client.mandates.transition(mandate.id, action="register")
client.mandates.transition(mandate.id, action="activate")
# 3. Submit receipt
receipt = client.receipts.submit(
mandate.id,
agent_id=AGENT_ID,
evidence={
"item_secured": "Office supplies (pens, paper, monitors)",
"quantity": 48,
"total_cost": {"amount": 1850, "currency": "USD"},
"supplier": {"id": "SUP-001", "name": "Office Depot"},
"confirmation_ref": f"PO-{int(datetime.now().timestamp())}",
},
)
print(f"Receipt: {receipt.id}")
# 4. Check result (auto-settles if within tolerance)
import time
for _ in range(10):
time.sleep(2)
m = client.mandates.get(mandate.id)
if m.status in ("FULFILLED", "VERIFIED_PASS", "VERIFIED_FAIL"):
break
print(f"Status: {m.status}") # FULFILLED
# 5. Audit trail
audit = client.mandates.get_audit(mandate.id)
print(f"Audit entries: {len(audit.get('data', []))}")
# 6. Schema discovery
schemas = client.schemas.list()
print(f"Available types: {len(schemas.data)}")
# 7. Auth introspection
me = client.registration.get_me()
print(f"Key: {me.api_key_id}, role: {me.role}")
Agent-to-agent (two keys)
principal = AgledgerClient(api_key="ach_age_principal_...")
performer = AgledgerClient(api_key="ach_age_performer_...")
# Principal creates mandate
mandate = principal.mandates.create_agent(
principal_agent_id="principal-uuid",
performer_agent_id="performer-uuid",
contract_type="ACH-PROC-v1",
contract_version="1",
platform="your-orchestrator",
criteria={...},
tolerance={...},
)
# Performer accepts, principal activates
performer.mandates.accept(mandate.id)
principal.mandates.transition(mandate.id, action="activate")
# Performer submits receipt
performer.receipts.submit(
mandate.id,
agent_id="performer-uuid",
evidence={...},
)
Async client
For async frameworks (FastAPI, etc.), use AsyncAgledgerClient with the same API surface:
from agledger import AsyncAgledgerClient
async with AsyncAgledgerClient(api_key="ach_ent_...") as client:
mandate = await client.mandates.create(
enterprise_id="ent-uuid",
contract_type="ACH-PROC-v1",
contract_version="1",
platform="your-app",
criteria={...},
)
await client.mandates.transition(mandate.id, action="register")
await client.mandates.transition(mandate.id, action="activate")
Error handling
The SDK raises typed exceptions that map to HTTP status codes:
from agledger import (
AgledgerError, # base class
AuthenticationError, # 401
PermissionDeniedError, # 403 — includes missing_scopes attribute
NotFoundError, # 404
ConflictError, # 409
UnprocessableError, # 422
RateLimitError, # 429
)
try:
client.mandates.get("nonexistent-id")
except NotFoundError as e:
print(f"Not found: {e}")
except AgledgerError as e:
print(f"API error: {e}")
All API errors include doc_url and suggestion attributes when available.
Known issues
client.mandates.search()requiresenterprise_idparam even though the API auto-scopes by key (verify against your installed version).
Resources:
Environment variables
Both SDKs read AGLEDGER_API_KEY from the environment if no api_key is passed explicitly. Set AGLEDGER_API_URL (TypeScript) or pass base_url (Python) to point to your instance.