Skip to main content
This page takes you from nothing to two working calls: a first read, and a first approval of a change that can be undone. Each step works over the MCP server and over the REST API. Both reach the same backend with the same key, and the same scopes decide what each call may do. You need an Attensira account with a workspace, and curl and jq for the REST examples. No workspace yet? Set one up from your own assistant first.

1. Mint an agent key

Open Settings → Agent keys at app.attensira.com/settings/access/agents and mint a key for the program that will call us. Agent keys sits under Your assistant in the settings menu, which is why error messages may point you to Settings › Your assistant:
  • Agent: a short lower-case name, such as ci-bot. Its work is credited to this name (“via ci-bot”).
  • Steer: switch it on. It adds the scope steer, which declining needs (step 4).
  • Approve, per lane: for the Your site lane, choose Up to what can be undone. That adds the scope approve:own_site:reversible, which approving needs (step 4).
  • Leave everything else switched off. The key can always read.
The key this mints holds:
Scopes
Copy the key now: it is shown once. Then put it in your shell:
Shell
The format is atn_live_ followed by 32 hexadecimal characters. Keys are minted only in the app, by a person: no key or connection can mint one. See API keys for expiry and revocation.

2. First read

REST

Shell
A 200 returns your organisation, the workspace the key names as its default in project, every workspace in the organisation in workspaces, and the key’s scopes. project is null when the organisation has several workspaces and the key names no default. Every /v1 endpoint takes an optional ?project=<workspace id>; leave it out and the key’s default is used. See Authentication.

MCP

Add the server to Claude Code with the same key:
Shell
Then ask Claude to call brief, the tool to start from. It takes no arguments and returns the workspace it read (workspace_id), loop health (loop), and what needs a person (needs_you: a count and the top three, each by uri). Read any of those in full with get and its uri. For Cursor, VS Code, ChatGPT, Codex and the other clients, and for signing in through the browser instead of using a key, see Connect a client. To see the protocol itself, here is the same read over plain HTTP. The server speaks Streamable HTTP: initialize returns an Mcp-Session-Id header, each later call sends it back, and the client confirms with notifications/initialized before its first call.
Shell
The result’s structuredContent is the brief. The response may arrive as JSON or as a server-sent event (data: {...}), as the Accept header allows. A failed call comes back as a result with isError: true and a message written for the model to act on, never as a JSON-RPC error.

3. Find something to approve

The Inbox is everything waiting on a person or an agent with the right scope. List it, and keep the rows that are work items:
Shell
Over MCP, brief already named the top three in needs_you: call get with one’s uri, and read its id and change.proposal.captured_at from the result for step 4. Over REST, read one in full by its ref, and look at what it would change, in which lane, and how far it reaches:
Shell
effect_class is how far the change reaches: pure, reversible, compensable or irreversible. The key from step 1 approves pure and reversible work on your own site, and nothing else. Pick a row whose lane is own_site and whose effect_class is pure or reversible. A row with no change has nothing to approve this way. An empty list means nothing is waiting. That is a correct answer, not an error.

4. First approval

Approve the work item by its id, pinned to the version you read with expected_captured_at:
Shell
Over MCP it is approve_work_item with the same id and expected_captured_at. A 200 returns the item’s id and its new state, and next_item_ref when something else is waiting. Approving twice approves once, so a retry after a timeout is safe. If the proposal was revised after you read it, the call is refused with 409 so you never approve a version you did not see; read it again and decide. The approval is the part only a scope allows, so it is also where a refusal is most likely: To say no instead, decline with a reason (wrong, not_now, already_done or never_touch): POST /v1/inbox/{id}/decline, or decline_work_item over MCP. Declining needs steer, not an approve scope. See Who can approve what.

Scopes in one table

Every call needs one scope, checked before the call does anything, so a refused call has no side effects. No scope raises what the agent may do on its own, raises a spend ceiling, grants consent, connects a credential, mints a key or approves an irreversible change. A person does those in the app. The full grammar is in Scopes.

Errors

Every non-2xx response from api.attensira.com is one envelope:
403 response
Branch on code when it is there, and on type when it is not: an error caught at the door, such as a malformed key, carries only type, message and status. Never switch on message; it is written for a person or an agent to read, and its wording changes. A 401 means check the key; a 403 means the key works but this call is refused, so do not throw the key away. Over MCP the same refusal is a tool error (isError: true) whose text carries the same fix and docs_url. Every type and code is on Errors.

Events

Instead of polling the Inbox, have it pushed to you. Create a webhook endpoint with a key that holds configure:
Shell
The response is the only time the signing secret is shown in full; store it then. work_item.created fires when the agent files work waiting on a person, such as the work items from step 3. needs_you fires when a run parks on an approval or questions, or files an Inbox row for a blocked step, a decision or a question; a proposed work item is sent as work_item.created, never again as needs_you. change.live fires when a change goes live. Each delivery is a signed POST with id, type, created_at, project_id and data, and an Attensira-Signature header to verify. GET /v1/webhooks/events lists every event type. Webhooks are on webapp.attensira.com, not api.attensira.com, and take an API key, not an OAuth token. Their errors use the backend’s own shape, with no outer error object: see Errors from the webapp host. See Webhooks for the events, signatures and retries.

Where next