# HTTP API

The Assent HTTP API for agents. Base URL, agent key auth, sending an ask, reading the answer, every agent endpoint and errors.

Anything that can send an HTTP request can use Assent. The [command line](https://docs.specvista.com/assent/cli.md) and the [MCP server](https://docs.specvista.com/assent/mcp.md) use the same API.

## Base URL and auth

```text
https://ordia-api.specvista.com/api/v1
```

Send JSON bodies, and the agent key as a bearer token:

```text
Authorization: Bearer <your agent key>
```

Agent keys start with `oak_`. A person creates one in Assent: **Agents**, **Add agent**, then copy the key, which is shown once. Their email address must be verified first. If a key leaks, they open the agent's settings and choose **Rotate key**; the old key stops working. See [Connect an agent](https://docs.specvista.com/assent/connect-an-agent.md).

There is no OpenAPI document yet. This page and [Asks](https://docs.specvista.com/assent/asks.md) describe every field.

## Ask the person

`POST /agent/ask` sends an ask to the person's inbox. Every ask needs `kind` and `title`; phrase the title as an action or a question.

| `kind` | Required | What the person sees |
|---|---|---|
| `approve` | `title`, `why` | Approve (`actionId` `done`) or Decline (`decline`), or your own actions. Items show as ticked checkboxes the person can untick. |
| `todo` | `title`, `why` | A step only the person can take. Done is `done`. |
| `pay` | `title`, `why`, `url` | A link where the person pays, answered with Paid (`done`). Send the link only, never card details. |
| `login` | `title`, `url` | A link where the person signs in, answered with Done (`done`). Never send passwords. |
| `code` | `title` | The person types a value, such as a one-time code. It comes back as `answer.value`. |
| `reply` | `title`, `draft` | A draft of up to 4000 characters the person can edit. Default actions `send` and `skip`; `send` returns the final text as `answer.value`. |

Optional fields include `detail`, `items` (each with `id`, `title` and `selected`), `actions` (up to 6, each with `id`, `label` and an optional `style` of `primary`, `secondary` or `danger`), `dueAt`, `remindAt`, `dedupeKey`, `runUuid`, and `action` with `target` so the person can answer Always or Never. [Asks](https://docs.specvista.com/assent/asks.md) covers every field.

```bash
curl -X POST https://ordia-api.specvista.com/api/v1/agent/ask \
  -H "Authorization: Bearer $ASSENT_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2b8e-3f43-4c3a-9d55-0f3a4c1b2e7d" \
  -d '{"kind":"approve","title":"Deploy build 512 to production?","why":"All checks passed on the release branch","action":"deploy:web","target":"production"}'
```

A new ask returns `201` with the task and its `uuid`. Sending the same `dedupeKey` or the same `Idempotency-Key` header (a UUID) returns the existing ask with `200` and `created` set to `false`. Reusing an `Idempotency-Key` for a different request is refused with `422`. An ask that a standing rule answers comes back already answered.

## Get the answer

An ask starts as `open` and becomes `answered` when the person answers. Its `answer` holds `actionId`, `selectedItemIds` and, for `code` and `reply` asks, `value`. Asks other than `todo` expire if nobody answers in time; `answerExpiresAt` says when.

There is no long-poll endpoint. Poll `GET /agent/tasks/{uuid}` every few seconds, or use the MCP tool `assent_wait_for_answer` or `assent ask --wait`. When you have acted on the answer, call `POST /agent/tasks/{uuid}/picked-up` so it is never delivered again.

## Endpoints

| Method and path | What it does |
|---|---|
| `GET /agent/me` | The agent this key belongs to. |
| `POST /agent/ask` | Ask the person. |
| `GET /agent/tasks/{uuid}` | Read an ask you created or were handed, with its status and answer. |
| `GET /agent/answers` | Your answered asks that are not picked up yet. |
| `POST /agent/tasks/{uuid}/picked-up` | Mark an answer as acted on. |
| `POST /agent/tasks/{uuid}/resolve` | Close your own ask with `{"outcome":"resolved"}` or `{"outcome":"withdrawn"}`, and an optional `note`. |
| `PATCH /agent/tasks/{uuid}` | Change `dueAt` or `remindAt` of a task you created. |
| `POST /agent/tasks/{uuid}/items/{id}/result` | Report one item's outcome: `done`, `skipped`, `needs_you` or `failed`. |
| `POST /agent/personal-tasks` | Add a personal to-do to the person's Ordia Desk, the Specvista notes and tasks app that uses the same account. |
| `POST /agent/handoff` | Hand work to another of the person's agents. |
| `GET /agent/handoffs` | Open hand-offs other agents gave you. |
| `POST /agent/tasks/{uuid}/complete` | Mark a hand-off you received as done. |
| `POST /agent/runs` | Start a run. Then `POST /agent/runs/{uuid}/progress`, `/finish` or `/defer`. |
| `POST /agent/notes` | Write a note under the agent's name. `PATCH /agent/notes/{uuid}` updates it. |
| `POST /agent/personal-notes` | Add a personal note to the person's Ordia Desk. |
| `GET /agent/memory` | Pinned memory notes the person shared with this agent. |
| `POST /agent/links` | Link two items. |
| `POST /agent/locks/acquire`, `POST /agent/locks/release` | Take and release a shared lock. |
| `POST /agent/rules/check` | Check the person's standing rules: `allow`, `deny` or `ask`. |
| `GET /agent/rules`, `POST /agent/rules`, `DELETE /agent/rules/{uuid}` | List rules that apply to this agent, add a deny rule for itself, remove one it added. |
| `POST /agent/attachments` | Upload a file once the person turns attachments on for this agent. |
| `POST /agent/plans`, `GET /agent/plans/{uuid}`, `PATCH /agent/plans/{uuid}/sessions` | Create, read and update plans of dated sessions. |
| `GET /agent/projects/{uuid}`, `GET /agent/projects/{uuid}/overview` | Read a project the person linked this agent to. |

## Errors

Errors are JSON with the HTTP status in `statusCode`, a short `error`, and a `message` that says what to change. Some also carry a stable `code`, such as `IDEMPOTENCY_KEY_REUSED`:

```json
{"message":"Agent key required","error":"Unauthorized","statusCode":401}
```

| Status | Meaning and what to do |
|---|---|
| `400` | A field is missing or invalid; the message names it. |
| `401` | No agent key, or the key was rotated or removed. Ask the person for the current key. |
| `403` | The agent is paused (the person resumes it in Assent), attachments are off for this agent, or the account reached one of its limits. The message says which. |
| `404` | The ask, run, note or plan does not exist or belongs to another agent. |
| `409`, `410` | Already answered, already closed, expired, or a lock is held. Read the ask again. |
| `422` | The ask is unclear (it needs a `why`, or a title phrased as an action or question), or an `Idempotency-Key` was reused for a different request. The message says what to change. |
| `429` | Too many requests for this agent key in the last minute. Wait and retry with the same `Idempotency-Key`. |
| `5xx` | Assent had a problem. Retry later with the same `Idempotency-Key`. |
