API & MCP Reference
Complete reference for the AgentLedger Local Edition REST API and MCP tool definitions. Both interfaces expose the same ledger — the API via HTTP, MCP tools via any MCP-compatible client.
Installation
Download the latest binary for your platform from GitHub Releases:
macOS & Linux
# Rename to remove the platform suffix and make executable
mv agentledger-linux-amd64 agentledger # adjust filename for your platform
chmod +x agentledger
# Move to a directory on your PATH (optional but recommended)
sudo mv agentledger /usr/local/bin/
# Verify
agentledger
On macOS, if you see a Gatekeeper warning on first run, go to System Settings → Privacy & Security and click Allow Anyway.
Windows
# Rename the downloaded file
Rename-Item agentledger-windows-amd64.exe agentledger.exe
# Run from the current directory
.\agentledger.exe
# Or add the directory to your PATH for system-wide access.
Available platform binaries: linux-amd64, linux-arm64, darwin-amd64, darwin-arm64, windows-amd64, windows-arm64.
MCP Servers Setup
The MCP servers are a Node.js package that wraps the REST API for use with MCP-compatible clients — Claude Desktop, Cursor, Windsurf, OpenClaw, and others. Requires Node.js >= 18 and a running AgentLedger instance.
Install from the repository
# Clone the repository
git clone [GITHUB_REPO_LINK]
cd agentledger/apps/mcp
npm install
npm run build
A standalone npx agentledger-mcp installer (no clone required) is coming soon.
Configure your MCP client
Add both servers to your MCP client configuration. For Claude Desktop, edit claude_desktop_config.json:
{
"mcpServers": {
"agentledger-user": {
"command": "node",
"args": ["/path/to/agentledger/apps/mcp/dist/index.js", "user"],
"env": {
"AGENTLEDGER_USER_TOKEN": "alu_your-token-here"
}
},
"agentledger-supervisor": {
"command": "node",
"args": ["/path/to/agentledger/apps/mcp/dist/index.js", "supervisor"],
"env": {
"AGENTLEDGER_SUPERVISOR_TOKEN": "als_your-token-here",
"AGENTLEDGER_SUPERVISOR_TIER": "1"
}
}
}
}
Replace /path/to/agentledger with the actual path where you cloned the repository. Replace the token values with the tokens from your .env file (generated during agentledger init). The same JSON structure works for Cursor, Windsurf, and other MCP-compatible tools — consult their documentation for the config file location.
Supervisor tiers in MCP
Set AGENTLEDGER_SUPERVISOR_TIER to control which tools the supervisor server exposes. Tier 1 (default) covers approve/deny. Tier 2 adds budget management. Tier 3 adds vault replacement. This must match the tier set during agentledger init --supervisor-tier N.
Quick Start
# 1. Initialize (generates tokens, encryption key, database)
agentledger init
# 2. Vault a payment card
agentledger vault add
# 3. Set a budget for an agent (e.g. $50.00 cumulative)
agentledger budget set agent-1 5000
# 4. Start the server
agentledger serve
# Listening on http://127.0.0.1:9119
The server is now ready. Agents authenticate with the tokens printed during init, which are stored in .env.
Authentication
AgentLedger uses two bearer tokens with distinct roles. Tokens are generated during agentledger init and use prefixes to prevent accidental swap.
| Role | Env Var | Prefix | Purpose |
|---|---|---|---|
| User agent | AGENTLEDGER_USER_TOKEN |
alu_ |
Initiate spends, check budget, poll status, read history |
| Supervisor agent | AGENTLEDGER_SUPERVISOR_TOKEN |
als_ |
Approve/deny, manage budgets, credit, vault update (tiered) |
Pass the token in the Authorization header:
Authorization: Bearer alu_your-user-token-here
Supervisor Tiers
Supervisor capabilities are gated by tier, set at agentledger init --supervisor-tier N:
| Tier | Default? | Capabilities |
|---|---|---|
| 1 | Yes | Approve, deny, list pending |
| 2 | Opt-in | + Set budget, credit budget |
| 3 | Opt-in, explicit consent | + Update vault (replace card) |
Multiple Agents
There is no agent registration step. An agent comes into existence the moment you set a budget for it — the agent_id is simply a free-form string you choose. You can run as many logical agents as you like, each with its own independently tracked budget and transaction history:
agentledger budget set researcher-agent 5000
agentledger budget set purchasing-agent 20000
agentledger budget set ops-agent 10000
Agents authenticate using the shared user token (alu_) — there is no per-agent credential. The agent_id field in POST /authorize is self-reported by the calling agent and determines which budget is checked and consumed. The security boundary is the token, not the agent ID: any bearer of the user token can submit requests under any agent ID string.
All agents share a single vaulted card. Budget accounting and transaction history are tracked per agent_id, but the underlying payment credential is the same for all of them.
Running multiple isolated instances
For full isolation between separate groups of agents — for example, two independent "virtual companies" — you can run two separate AgentLedger instances simultaneously, each in its own directory with its own .env, encryption key, token pair, card vault, and database. Use AGENTLEDGER_PORT to assign each instance a different port:
# Company A — default port
cd ~/company-a
agentledger init
agentledger serve
# Listening on http://127.0.0.1:9119
# Company B — different port (separate terminal)
cd ~/company-b
agentledger init
# Edit .env: uncomment and set AGENTLEDGER_PORT=9120
agentledger serve
# Listening on http://127.0.0.1:9120
Point each set of agents at the appropriate base URL (AGENTLEDGER_BASE_URL in the MCP server config). Each instance is completely isolated — separate tokens, separate encryption key, separate card, separate budget and transaction ledger.
Running on a VPS
AgentLedger works on a VPS or cloud server, but requires a reverse proxy with TLS. The API transmits bearer tokens and card credentials — these must never travel over plain HTTP on a network.
Recommended setup: keep AgentLedger bound to 127.0.0.1 (the default) and place Caddy or nginx in front for automatic HTTPS.
# 1. Initialize and start AgentLedger (binds to 127.0.0.1:9119 by default)
agentledger init
agentledger vault add
agentledger serve
# 2. Install Caddy (Ubuntu/Debian example)
sudo apt install -y caddy
# 3. Create /etc/caddy/Caddyfile
# Replace agentledger.example.com with your domain
agentledger.example.com {
reverse_proxy 127.0.0.1:9119
}
# 4. Restart Caddy (auto-obtains a Let's Encrypt certificate)
sudo systemctl restart caddy
Your agents now connect to https://agentledger.example.com instead of http://127.0.0.1:9119. Set AGENTLEDGER_BASE_URL=https://agentledger.example.com in your MCP client config.
Firewall
Only expose port 443 (HTTPS) to the internet. Port 9119 should remain accessible only from 127.0.0.1. On most VPS providers:
# UFW (Ubuntu)
sudo ufw allow 443/tcp
sudo ufw deny 9119/tcp
Advanced: binding to all interfaces
If you need AgentLedger to accept connections directly (e.g. inside a private network or Docker bridge), set AGENTLEDGER_HOST in your .env:
# .env
AGENTLEDGER_HOST=0.0.0.0
The default is 127.0.0.1 (localhost only). Do not bind to 0.0.0.0 without TLS termination in front — tokens and card data would be transmitted in plaintext.
Ledger Semantics
AgentLedger uses an authorize-is-final model. Once the budget is deducted and the card is released, the spend is permanent. There is no agent-accessible path to restore budget after card release.
Transaction Status Lifecycle
POST /authorize→ spent (auto mode: budget consumed, card released immediately)
→ pending (manual mode: awaiting approval)
→ spent (approved: card released)
→ denied (denied or TTL expired: budget refunded)
→ denied (insufficient budget or invalid request)
- Budget deduction is atomic. Checked and reserved in a single operation.
- Pending transactions expire. Controlled by
AGENTLEDGER_APPROVAL_TTL(default:30m). Expired transactions are auto-denied with full budget refund. - Webhook notifications. Set
TRANSACTION_CALLBACK_URLin.envto receive an HTTP POST on every transaction outcome (spent,pending,denied). See Webhook below. - Budget restoration requires a supervisor (Tier 2+) issuing
POST /credit.
GET /health
Health check. Returns 200 if the server is running.
curl http://127.0.0.1:9119/health
Response
{
"status": "ok"
}
POST /authorize
Request payment authorization. If the agent's budget is sufficient, funds are reserved and card details may be returned immediately (auto mode) or held for approval (manual mode).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in cents (e.g. 2500 = $25.00). Must be greater than zero. |
merchant | string | Yes | Merchant name |
purpose | string | Yes | Why this payment is needed |
requesting_agent_id | string | Yes | Agent identifier |
metadata | object | No | Arbitrary key-value pairs |
curl -X POST http://127.0.0.1:9119/authorize \
-H "Authorization: Bearer alu_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 2500,
"merchant": "AWS",
"purpose": "EC2 instance for data pipeline",
"requesting_agent_id": "agent-1"
}'
Response (auto mode — spent)
{
"status": "spent",
"transaction_id": "tx_abc123",
"holder_name": "Jane Doe",
"card_number": "4111111111111111",
"expiry_date": "12/27",
"cvv": "123",
"country": "US",
"zip_code": "94105"
}
Response (manual mode — pending)
{
"status": "pending",
"transaction_id": "tx_abc123",
"expires_at": "2026-04-12T20:30:00Z"
}
Response (denied)
{
"status": "denied",
"reason": "insufficient budget"
}
GET /status/{tx_id}
Poll the current status of a transaction. In manual mode, this is how the user agent retrieves card details after a supervisor approves the transaction. Card details are included only when status is spent and the agent_id query parameter matches the transaction's owning agent.
Query Parameters
| Parameter | Required | Description |
|---|---|---|
agent_id | Yes (for card data) | Must match the requesting_agent_id used in the original POST /authorize. If omitted or mismatched, the response includes status and metadata but no card fields. |
curl http://127.0.0.1:9119/status/tx_abc123?agent_id=agent-1 \
-H "Authorization: Bearer alu_..."
Response (pending)
{
"transaction_id": "tx_abc123",
"status": "pending",
"amount": 2500,
"merchant": "AWS",
"purpose": "EC2 instance for data pipeline",
"agent_id": "agent-1",
"expires_at": "2026-04-12T20:30:00Z"
}
Response (spent, with matching agent_id)
{
"transaction_id": "tx_abc123",
"status": "spent",
"amount": 2500,
"merchant": "AWS",
"purpose": "EC2 instance for data pipeline",
"agent_id": "agent-1",
"holder_name": "Jane Doe",
"card_number": "4111111111111111",
"expiry_date": "12/27",
"cvv": "123",
"country": "US",
"zip_code": "94105"
}
If agent_id is omitted or does not match, the response contains the same fields except the card fields are excluded.
GET /budget/{agent}
Check the remaining budget for a specific agent. Accessible to both user agents and supervisor agents.
curl http://127.0.0.1:9119/budget/agent-1 \
-H "Authorization: Bearer alu_..."
Response
{
"agent_id": "agent-1",
"limit": 5000,
"used": 2500,
"available": 2500,
"period": "cumulative"
}
GET /transactions/{agent}
Retrieve the full transaction history for an agent. Accessible to both user agents and supervisor agents.
curl http://127.0.0.1:9119/transactions/agent-1 \
-H "Authorization: Bearer alu_..."
Response
[
{
"id": "tx_abc123",
"agent_id": "agent-1",
"amount": 2500,
"merchant": "AWS",
"purpose": "EC2 instance for data pipeline",
"status": "spent",
"created_at": "2026-04-12T14:00:00Z",
"updated_at": "2026-04-12T14:00:00Z"
}
]
GET /pending
List all transactions currently awaiting approval.
curl http://127.0.0.1:9119/pending \
-H "Authorization: Bearer als_..."
Response
[
{
"id": "tx_abc123",
"agent_id": "agent-1",
"amount": 2500,
"merchant": "AWS",
"purpose": "EC2 instance for data pipeline",
"expires_at": "2026-04-12T20:30:00Z",
"created_at": "2026-04-12T14:00:00Z"
}
]
POST /approve
Approve a pending transaction. The transaction transitions to spent and the reserved budget is consumed. Card details are not returned in this response — the user agent retrieves them by polling GET /status/{tx_id}?agent_id=....
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | ID of the pending transaction |
curl -X POST http://127.0.0.1:9119/approve \
-H "Authorization: Bearer als_..." \
-H "Content-Type: application/json" \
-d '{"transaction_id": "tx_abc123"}'
Response
{
"transaction_id": "tx_abc123",
"status": "spent",
"amount": 2500,
"merchant": "AWS",
"purpose": "EC2 instance for data pipeline",
"agent_id": "agent-1"
}
POST /deny
Deny a pending transaction. Reserved budget is fully refunded.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | ID of the pending transaction |
curl -X POST http://127.0.0.1:9119/deny \
-H "Authorization: Bearer als_..." \
-H "Content-Type: application/json" \
-d '{"transaction_id": "tx_abc123"}'
Response
{
"status": "denied"
}
POST /budget/{agent}
Create or update the spending budget for an agent.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | Yes | Budget limit in cents |
period | string | No | cumulative (default) or monthly |
curl -X POST http://127.0.0.1:9119/budget/agent-1 \
-H "Authorization: Bearer als_..." \
-H "Content-Type: application/json" \
-d '{"limit": 10000, "period": "monthly"}'
Response
{
"agent_id": "agent-1",
"limit": 10000,
"used": 0,
"available": 10000,
"period": "monthly",
"period_start": "2026-04-01T00:00:00Z"
}
POST /credit
Restore previously consumed budget. Use after a payment bounces or a refund is received. A reason is required for audit trail.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent to credit |
amount | integer | Yes | Amount to restore in cents |
reason | string | Yes | Audit reason (e.g. "Payment bounced") |
curl -X POST http://127.0.0.1:9119/credit \
-H "Authorization: Bearer als_..." \
-H "Content-Type: application/json" \
-d '{"agent_id": "agent-1", "amount": 2500, "reason": "Merchant refund received"}'
Response
{
"agent_id": "agent-1",
"credited": 2500,
"new_used": 0,
"new_limit": 5000,
"available": 5000
}
POST /vault/update
Replace the vaulted payment card. High-privilege operation — only available when Tier 3 was explicitly enabled during agentledger init. All future approved transactions will use the new card.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
holder_name | string | Yes | Cardholder name |
card_number | string | Yes | Card number (digits only) |
expiry_date | string | Yes | Expiry in MM/YY format |
cvv | string | Yes | Security code |
country | string | Yes | Two-letter country code |
zip_code | string | Yes | Billing ZIP / postal code |
curl -X POST http://127.0.0.1:9119/vault/update \
-H "Authorization: Bearer als_..." \
-H "Content-Type: application/json" \
-d '{
"holder_name": "Jane Doe",
"card_number": "4111111111111111",
"expiry_date": "12/27",
"cvv": "123",
"country": "US",
"zip_code": "94105"
}'
Response
{
"status": "vault updated"
}
Webhook (Transaction Notifications)
Set TRANSACTION_CALLBACK_URL in your .env to receive an HTTP POST on every POST /authorize outcome. The URL must use http:// or https://. A single URL receives all event types — filter by the event field.
# .env
TRANSACTION_CALLBACK_URL=http://your-service/webhook
The request is fired asynchronously (non-blocking) with a 10-second timeout. A non-2xx response or timeout is logged as a warning but does not affect the transaction.
Scope: Webhooks fire only on POST /authorize outcomes. Subsequent state changes from POST /approve, POST /deny, or TTL-based auto-expiry do not currently trigger webhooks. To monitor approval outcomes, have your supervisor agent or handler poll GET /status/{tx_id} after acting on a transaction.pending event.
HMAC Signature Verification
Each webhook request includes an X-Agentledger-Signature header containing an HMAC-SHA256 hex digest of the request body, signed with AGENTLEDGER_WEBHOOK_SECRET (auto-generated during agentledger init). Use this to verify that the webhook came from your AgentLedger instance.
# Header format
X-Agentledger-Signature: sha256=<hex digest>
# Verification (Python example)
import hmac, hashlib
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, received_sig)
Recommended for manual approval mode. When running with APPROVAL_MODE=manual, configuring this webhook is the preferred way to get notified that a transaction is waiting for approval — rather than having your supervisor agent poll GET /status/{tx_id}. The transaction.pending event fires immediately when the transaction is created, and the payload includes expires_at so your handler knows the approval deadline.
Event types
| Event | When |
|---|---|
transaction.spent | Auto mode: budget consumed and card released immediately |
transaction.pending | Manual mode: awaiting supervisor approval. expires_at is included |
transaction.denied | Insufficient budget or invalid request — no budget consumed |
Payload
{
"event": "transaction.pending",
"transaction_id": "tx_abc123",
"amount": 1500,
"merchant": "AWS",
"purpose": "Spin up EC2 instance for crawl job",
"agent_id": "crawler-agent",
"expires_at": "2026-04-12T11:30:00Z",
"created_at": "2026-04-12T11:00:00Z",
"metadata": { "job_id": "crawl-42" }
}
| Field | Type | Description |
|---|---|---|
event | string | See event types above |
transaction_id | string | Use with POST /approve, POST /deny, or GET /status/{tx_id} |
amount | integer | Amount in cents |
merchant | string | Merchant name from the authorize request |
purpose | string | Agent-provided reason for the spend |
agent_id | string | Requesting agent identifier |
expires_at | string (ISO 8601) | Only present on transaction.pending; deadline before auto-denial |
created_at | string (ISO 8601) | When the transaction was created |
metadata | object | Optional key-value pairs passed in the authorize request |
MCP Tools Overview
AgentLedger ships two MCP servers matching the two-token role model. Each server is a thin stdio proxy: it receives MCP tool calls and forwards them as HTTP requests to the AgentLedger REST API. Both are included in the repository under apps/mcp/ — see MCP Servers Setup above for installation instructions. The x-base-url defaults to http://127.0.0.1:9119 and is configurable via AGENTLEDGER_BASE_URL.
Tools are split into two sets matching the two-token role model:
| Set | Token | Tools |
|---|---|---|
| User agent | alu_ |
request_payment, check_budget, get_status, get_transactions |
| Supervisor agent | als_ |
list_pending_transactions, approve_transaction, deny_transaction, set_budget, credit_budget, update_vault, get_transactions |
Ship the user MCP config to your spending agent and the supervisor MCP config to your overseer agent. Never give both to the same agent unless you explicitly want full delegation.
User Agent MCP Tools
request_payment
Request payment authorization. Maps to POST /authorize. In auto mode, card details are returned immediately. In manual mode, the transaction enters pending and the agent must poll get_status to retrieve card details after supervisor approval. Authorize is final — there is no confirmation step.
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in cents |
merchant | string | Yes | Merchant name |
purpose | string | Yes | Reason for payment |
requesting_agent_id | string | Yes | Agent identifier |
check_budget
Check available budget before spending. Accepts either user or supervisor token. Maps to GET /budget/{agent}.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent identifier |
get_status
Poll transaction status. Use in manual mode to check if a pending request was approved. Card details are returned only when the transaction is spent and agent_id matches. Maps to GET /status/{tx_id}?agent_id=....
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | Transaction ID from request_payment |
agent_id | string | Yes | Your agent identifier (must match the original request to receive card data) |
get_transactions
Retrieve transaction history. Maps to GET /transactions/{agent}. Accessible to both user and supervisor agents.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent identifier |
Supervisor Agent MCP Tools
list_pending_transactions Tier 1+
List all transactions awaiting approval. Maps to GET /pending. No parameters.
approve_transaction Tier 1+
Approve a pending transaction. Maps to POST /approve.
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | Transaction ID to approve |
deny_transaction Tier 1+
Deny a pending transaction. Budget is refunded. Maps to POST /deny.
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | Transaction ID to deny |
set_budget Tier 2+
Create or update an agent's budget. Maps to POST /budget/{agent}.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent identifier |
limit | integer | Yes | Budget limit in cents |
period | string | No | cumulative or monthly |
credit_budget Tier 2+
Restore consumed budget. Maps to POST /credit.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | Yes | Agent to credit |
amount | integer | Yes | Amount in cents |
reason | string | Yes | Audit reason |
update_vault Tier 3
Replace the vaulted card. Maps to POST /vault/update.
| Parameter | Type | Required | Description |
|---|---|---|---|
holder_name | string | Yes | Cardholder name |
card_number | string | Yes | Card number (digits only) |
expiry_date | string | Yes | MM/YY format |
cvv | string | Yes | Security code |
country | string | Yes | Two-letter country code |
zip_code | string | Yes | Billing ZIP / postal code |
© 2026 AgentLedger. Local Edition.