Quickstart
This walks through a first agent integration: a key with the right scopes, a read, a dry run, a write that posts, and one that waits for approval. Every example uses curl against https://api.evenbead.com; the same operations are MCP tools (see MCP setup).
1. Get a key
A company's owner signs in to the web app at https://app.evenbead.com with their owner key, then creates people and agents in Settings. Through the API, an owner (or any person with the admin scope) registers an agent and mints its key:
export EVENBEAD_KEY="eb_..." # the owner's key; keep it out of shell history and source control
curl -s https://api.evenbead.com/v1/agents \
-H "Authorization: Bearer $EVENBEAD_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: register-categorizer-001" \
-d '{"name":"categorizer","scopes":["read","propose"],"posting_threshold_cents":50000}'
curl -s https://api.evenbead.com/v1/keys \
-H "Authorization: Bearer $EVENBEAD_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: categorizer-key-001" \
-d '{"principal_type":"agent","agent_id":"<agent id>","scopes":["read","propose"],"expires_in_days":30}'
The response holds the key once. Only its hash is stored, so a lost key is replaced, not recovered.
2. Scopes
| Scope | Allows |
|---|---|
read | Every read: accounts, reports, documents, the audit log, exports |
propose | Writes that go through policy: journal entries, documents, bank categorization |
approve | Approving or rejecting proposals (never your own), finishing reconciliations |
admin | Company setup: accounts, periods, people, agents, keys |
Give an agent the least it needs. Agents should almost never hold admin. An agent's effective scopes are the key's scopes limited by the agent's own.
3. Read something
curl -s https://api.evenbead.com/v1/me -H "Authorization: Bearer $AGENT_KEY"
curl -s "https://api.evenbead.com/v1/accounts" -H "Authorization: Bearer $AGENT_KEY"
/v1/me shows who you are, your scopes, your company and when your key expires.
4. Dry run, then write
Any write accepts "dry_run": true. Nothing is written and no idempotency key is needed:
curl -s https://api.evenbead.com/v1/journal-entries/propose \
-H "Authorization: Bearer $AGENT_KEY" \
-H "X-Agent-Model: your-model-name-and-version" \
-H "Content-Type: application/json" \
-d '{"entry_date":"2026-09-03","memo":"Office supplies","dry_run":true,
"lines":[{"account":"6300","debit_cents":4299},{"account":"1000","credit_cents":4299}]}'
The answer has outcome: "dry_run", would (post, queue_for_approval or be_refused), the policy verdict with its reasons, the period, the affected balances and any validation errors. Drop dry_run and add an Idempotency-Key to write it:
curl -s https://api.evenbead.com/v1/journal-entries/propose \
-H "Authorization: Bearer $AGENT_KEY" \
-H "X-Agent-Model: your-model-name-and-version" \
-H "X-Agent-Run-Id: run-2026-09-03-a" \
-H "Idempotency-Key: supplies-2026-09-03-4299" \
-H "Content-Type: application/json" \
-d '{"entry_date":"2026-09-03","memo":"Office supplies",
"lines":[{"account":"6300","debit_cents":4299},{"account":"1000","credit_cents":4299}]}'
201withoutcome: "posted": within policy, posted.202withoutcome: "pending_approval": a proposal is waiting for a person.
5. Idempotency keys
- Required on every write except a dry run: 8 to 200 characters of
A-Z a-z 0-9 . _ : -. - Same key and same request: the original response comes back with the header
Idempotency-Replayed: true. Retry freely after a timeout. - Same key with a different request:
409 idempotency_conflict. - Keys are kept per company for at least 30 days. Derive them from your own data (a bank line id, an invoice number) so a crashed run can safely start over.
Writes that set a value (for example a plan or a setting) say so in the reference; they need no key because repeating them leaves the same state.
6. Proposals and approval thresholds
Each agent has a posting_threshold_cents. An agent write becomes a proposal instead of a posting when any of these apply:
| Reason | When |
|---|---|
over_threshold | The entry total is above the agent's threshold |
sensitive_account | It touches an equity account |
period_soft_locked | The period is soft-locked (only a person may post, with a reason) |
low_confidence | The agent sent confidence below 0.7 |
new_counterparty | An invoice, bill or payment for a customer or vendor with no posted documents yet |
People see proposals in the web app's approval queue. Through the API:
curl -s "https://api.evenbead.com/v1/proposals?status=pending" -H "Authorization: Bearer $APPROVER_KEY"
curl -s https://api.evenbead.com/v1/proposals/<id>/approve -X POST \
-H "Authorization: Bearer $APPROVER_KEY" -H "Idempotency-Key: approve-<id>" -H "Content-Type: application/json" -d '{}'
Rejecting needs a reason, which stays on the record. Nobody approves their own proposal. Hard-locked periods refuse every write, in the database.
7. Rate limits
Requests are limited per key, per company for agents, and per address. Plan limits: Solo 60, Business 300, Advanced 1,200 requests per minute. A key can carry its own lower budget (rate_limit_rpm). Over the limit you get 429 with error.type: "rate_limited" and a Retry-After header in seconds: wait that long, then retry with the same idempotency key.
8. Key expiry and rotation
- People's keys last 365 days; agents' keys 30 days by default and at most 90.
/v1/mereportskey.expires_at. Rotate before then:
curl -s https://api.evenbead.com/v1/keys/<key id>/rotate -X POST \
-H "Authorization: Bearer $AGENT_KEY" -H "Idempotency-Key: rotate-2026-10" \
-H "Content-Type: application/json" -d '{"overlap_seconds":3600}'
The new secret is returned once. The old key keeps working for the overlap window (default 24 hours, at most 7 days), then stops. An agent can rotate its own key; admins rotate any key in the company. Revoking an agent stops all of its keys on the next request.
Next
- Authentication and firms: sessions, accounting firms acting in client books.
- MCP setup: connect Claude and other agents.
- API reference and MCP tools.