# API overview

Source: https://amolfi.com/docs#api

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.

API keys, the CLI and MCP clients are part of Pro and up. On Starter a key is refused with `402 API_KEYS_NOT_ON_PLAN` before any work runs. The `ultrawork` effort is part of Ultra and Enterprise, and the Moonshot working style is part of Max and Ultra, a Team+ seat, and Enterprise; a plan that names one it does not carry is refused with `402` and the door it opens on, never quietly run at a smaller setting.

### 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",
  "working_style": "autonomous",
  "effort": "normal"
}
```

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_REQUIRED` when the token lacks the scope, `FORBIDDEN` when 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-Key` conflict (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.

[Authentication](https://amolfi.com/docs/api/authentication)[Runs](https://amolfi.com/docs/api/runs)[API + CLI](https://amolfi.com/model/api)

```
curl https://api.amolfi.com/v1/tools/finance_list_invoices \
  -H "Authorization: Bearer $AMOLFI_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"status":"open","limit":3}'
```

200 OK · example data.invoices

```
[
  {
    "id": "11111111-1111-4111-8111-111111111111",
    "invoice_number": "INV-1042",
    "customer_name": "Acme Studio",
    "currency": "USD",
    "status": "sent",
    "total_cents": 420000,
    "outstanding_cents": 420000
  }
]
```

Illustrative invoice fields. The full result includes status, data.receipt and meta; check meta.truncated.
