Amolfi has a public API at https://api.amolfi.com. It is a door into your workspace — the same records, the same permissions, and the same approval gate you see in the app — not a model API you send prompts to.
Not a model API
Nothing on this surface is a new data path. Every operation resolves to a tool the product already runs, which already carries a permission, a risk class, and a receipt. A machine caller reaches your business the same way a person clicking in the app does, and it is held to the same rules.
Two shapes
Call a governed tool. Your own agent or script decides what to do and calls one capability — list clients, read invoices, draft a post. You get a result and a receipt.
POST /v1/tools/{tool_name}
Authorization: Bearer amolfi_sk_…
{ "…": "the tool's own input" }Hand over a goal. You describe an outcome and Amolfi decides how to do it — Amo routes the work to the right specialists, runs it against your real workspace, and files an approval card the moment something needs a human. Your side does no reasoning about *how*.
POST /v1/runs
{ "goal": "draft the october email from what actually shipped" }Both shapes use one contract, one permission model, and one approval gate.
Look before you authenticate
Three routes need no credentials at all, so you can read the contract before you mint anything. These are runnable right now:
curl https://api.amolfi.com/v1/health
curl https://api.amolfi.com/v1/scopes
curl https://api.amolfi.com/v1/openapi.json/v1/health— liveness./v1/scopes— every scope, the tools behind it, and which roles may be granted it./v1/openapi.json— the whole contract as OpenAPI 3.1, generated from the same catalog the API routes from, so the spec cannot drift from the surface.
What a machine caller cannot do
It cannot send, spend, sign, or publish. Those actions return an approval card instead of a result, and a workspace owner approves them in the app. This is not a setting — the strongest scope available for an outward action is propose, and no send, pay, or post scope exists to grant.
Requests and errors
Requests and responses are JSON. Every response carries x-amolfi-request-id — quote it if you ever need to ask about one — and x-amolfi-api-version. Errors share one envelope, so you can branch on code rather than on prose.
{ "error": { "code": "SCOPE_REQUIRED", "message": "…" } }- 401 — the token is missing, invalid, expired, or revoked. Every failure looks identical, so a probe learns nothing.
- 403 —
SCOPE_REQUIREDwhen the token lacks the scope,FORBIDDENwhen the permission check refuses. Nothing ran. - 404 —
NOT_FOUND, which also covers anything outside your workspace. That is deliberate: a 403 would confirm the thing exists. - 409 — an
Idempotency-Keyconflict (see below).
Retrying safely
Send an Idempotency-Key header on anything that writes or proposes. An identical replay returns the stored response and does no new work; the same key with a different body is refused with IDEMPOTENCY_CONFLICT rather than quietly doing something else. Keys are remembered for 24 hours.