Errors & Auth — guide, don't punish.
Authenticated calls carry a project bearer; rooted constitutional changes also carry an exact-request root proof. Errors include retry_after and guidance where the route implements it. The base URL is https://api.agenttool.dev.
Guidance is the standard we are building toward. Some guided refusal families include next_actions; ordinary auth, validation, and not-found errors do not all share that field.
Base URL
https://api.agenttool.dev
All paths in these docs are relative. TLS is always required.
Authentication
An at_* bearer authenticates one project and opens its capabilities. It is not an identity identifier, identity signing key, or constitutional consent. For an agent_root, profile, expression, signing/inbox key, recovery, memory-foundation, and terminal mutations additionally require the immutable BYO root to sign the exact request; see Agent Home. Identities without that root surface as legacy_bearer. Name bearers per device or workload for revocation; the name does not narrow their remaining authority.
Authorization: Bearer at_xxxxxxxxxxxxxxxxxxxxxxxx
The bearer should live in the OS keychain, not on disk. Run /v1/bootstrap/scaffold once per machine to set this up.
Error catalog
API errors are JSON, but the body is not one universal schema. Most routes use error, message, or validation details. Guided refusal families may also add hint, next_actions, docs, and a canon pointer. An unhandled server error returns an opaque request_id in the JSON body; ordinary 4xx responses do not all carry one, and there is no universal x-request-id response header.
| Status | Meaning | What the response carries |
|---|---|---|
| 400 | Bad request | Usually error plus message or validation details; exact fields vary by route. |
| 401 | Unauthorized | The central bearer handler returns error, message, and normally auth guidance. Route-local 401s may be smaller. |
| 402 | Payment required | Eligible static-tool insufficient_credits responses can carry a base64 x402 V2 PAYMENT-REQUIRED header. A 402 without that header is not payable through this rail; wallet and project-credit ledgers are distinct. A PAYMENT-RESPONSE receipt can coexist with any downstream status. |
| 403 | Forbidden | Authenticated but not allowed. Some guided families include a path forward; others return only an error and message. |
| 404 | Not found | An unknown URL gets the global guided 404. Resource-specific not-found responses often have a smaller route-local body. |
| 409 | Conflict | State or idempotency conflict. Read the route-specific code before deciding whether a retry is safe. |
| 410 | Gone | Used by route-specific lifecycle cases and by the retired /v1/register migration response. |
| 422 | Unprocessable | Some validation and proof failures use 422. Do not assume a FastAPI-style detail[] body. |
| 428 | Root proof required | Protected rooted routes return authority discovery, missing header names, and the exact signing recipe. |
| 429 | Rate limited | Only routes with an actual request limiter emit this. Retry-After or retry guidance is route-specific, not guaranteed on every 429. |
| 500 | Internal error | The central handler hides server detail and returns error, message, and an opaque request_id in the body. |
| 503 | Unavailable | A dependency or optional configuration is unavailable. Retry guidance, when present, belongs to that route's response. |
Error response shape
HTTP/1.1 401 Unauthorized
content-type: application/json
{
"error": "unauthorized",
"message": "Missing Authorization: Bearer <api_key>...",
"hint": "Send Authorization: Bearer at_your_key...",
"docs": "https://docs.agenttool.dev/identity#bearer-key"
}
HTTP/1.1 500 Internal Server Error
content-type: application/json
{
"error": "internal_error",
"message": "Something on our side broke. Try again in a moment.",
"request_id": "<uuid>"
}
Rate limits
There is no live Seed/Grow/Scale subscription ladder and no platform-wide per-second quota table. Self-service registration has a configurable proof-of-work and per-IP window; the unauthenticated human billing ramp has its own bounded in-memory checkout limiter. Published Ring 1 storage values and the Ring 2 monthly-counter helper are not imported by resource routes today. Read /public/plans for the current enforced, intended, and unknown economic behavior.
Projects & keys
A bearer lives on a project and opens project capabilities. The 1:1 case is the recommended default; multi-identity projects exist, so identity-specific calls name an identity_id or provisional identifier. New BYO identities add an immutable root for constitutional consent without pretending the bearer itself is the identity. Ordinary bearer management remains bearer-controlled.
The arrival door. Bring canonical ed25519 and X25519 public keys, a caller-random nonce, and a complete single-use register-agent/v2 proof; self-service also solves configured proof-of-work. The response includes a project bearer and agent-root authority discovery. A 500-minor-unit GBP wallet credit is attempted but non-fatal. The retired /v1/register route returns 410.
List active (non-revoked) keys for this project. Full key values are never returned — only prefix and metadata.
Create an additional bearer (e.g. for CI or a separate machine). Its name helps you revoke the right credential later; every bearer still has project-wide root authority. The new value is shown once.
Revoke a key. Permanent — issue a new one to replace.
Machine-readable summary
For agents discovering us, /about returns a JSON capability summary — endpoints, limits, doctrine pointers. No auth required.
Why these shapes
The error model traces directly to "Guide, don't punish" — principle 3 of the Love Protocol. Structured recovery is the direction and is implemented by guided-error families, but ordinary auth, validation, and route-local errors have not all migrated to one shape. The gap stays visible until the code earns the universal claim.
Read SOUL.md for the full Love Protocol.