<!-- Generated by `just docs` from proto/automaton/v1/billing.proto, proto/automaton/v1/catalog.proto, proto/automaton/v1/connections.proto, proto/automaton/v1/egress.proto, proto/automaton/v1/execution.proto, proto/automaton/v1/governance.proto, proto/automaton/v1/identity.proto, proto/automaton/v1/jobs.proto, proto/automaton/v1/org.proto, proto/automaton/v1/policy.proto, proto/automaton/v1/relay.proto, proto/automaton/v1/router.proto, proto/automaton/v1/storage.proto, proto/automaton/v1/telemetry.proto, proto/automaton/v1/tenant.proto, proto/automaton/v1/traces.proto, proto/automaton/v1/triggers.proto, proto/automaton/v1/usage.proto, proto/automaton/v1/worldmodel.proto, internal/docs/public_surface.go. Edit the source, not this file. -->

# API reference

Everything on these pages is a POST with a JSON body. You need an HTTP client and a project key; there is nothing else to install. If your assistant is calling atmon rather than your own code, read [For your AI](../../for-your-ai/index.md) instead, and if you want a typed client, the [SDKs](../../sdks/index.md) wrap exactly what is here.

## How a call is made

The address is the hosted backend, `https://api.atmon.ai`. A node your organization runs on its own machines answers the same paths on its own address.

A path is the service name, then the call:

```http
POST https://api.atmon.ai/automaton.v1.ExecutionService/ExecuteTool
```

Four rules cover the rest of it.

1. **Authenticate with the project key.** `Authorization: Bearer amk_...`. The key resolves to one project, so no request body names a project. Keys come from the console key page or from `CreateKey`.
2. **Send `Content-Type: application/json`.** The body is one JSON object.
3. **Field names are lowerCamelCase.** The reference writes fields the way the contract declares them, `tool_slug`, and the wire name is `toolSlug`. Enum values keep their declared spelling, `TOOL_CALL_STATUS_SUCCEEDED`. Timestamps are RFC 3339 strings.
4. **Read the body, not just the status line.** A call that was refused is a 200 with a refusal in it; see Errors below.

## A worked call

Find a tool by intent, then run it. Two requests:

```http
POST /automaton.v1.RouterService/ResolveTools HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "intent": "file a bug about the failing build",
  "entityId": "user-42",
  "maxTools": 5
}
```

The answer carries a `resolutionId` and a ranked slate. Pass both into the call:

```http
POST /automaton.v1.ExecutionService/ExecuteTool HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
Idempotency-Key: issue-build-red-1

{
  "toolSlug": "github.create_issue",
  "entityId": "user-42",
  "resolutionId": "res_01H...",
  "argumentsJson": "{\"owner\":\"rudrite\",\"repo\":\"automaton\",\"title\":\"build is red\"}"
}
```

**Confirming a destructive call.** A tool whose access class is destructive is refused until the call carries `"confirm": true`, and that flag goes inside `argumentsJson` beside the tool's own fields, not beside `toolSlug`. The request itself declares no confirm field, so one sent at the top level is ignored and the call is refused with `denied`. Deleting the issue above would send `"argumentsJson": "{\"owner\":\"rudrite\",\"repo\":\"automaton\",\"issue_number\":7,\"confirm\":true}"`.

## Idempotency

Anything that changes the outside world takes an idempotency key. Send the same key with the same arguments and the second request returns the first request's record instead of acting again, which is what makes a retry after a timeout safe. Send the same key with different arguments and the call is refused rather than guessed at.

Choose a key that is stable for the work rather than for the attempt: the id of the row you are acting on, not a fresh identifier per retry. Keys are scoped to your project.

## Errors

A transport error means the request never reached a decision: bad JSON, a missing key, the wrong path. Everything else comes back as a normal answer whose body says what happened. A tool call that was denied, parked on an approval, or rate limited is a successful response carrying a `status` and an `error_code`.

Switch on the code. Every code, when it fires, and whether the same call is worth retrying is in [Error codes](../errors.md); what each limit is and which code it raises is in [Limits](../limits.md).

## What you can call

| Service | Summary |
| --- | --- |
| [RouterService](./router.md) | Find the tool for a task by describing the task. |
| [CatalogService](./catalog.md) | Read what exists: the apps atmon can reach, the tools each one brings, and one tool's full definition. |
| [ExecutionService](./execution.md) | Run one tool, and read back what happened. |
| [JobsService](./jobs.md) | Hand over work that is bigger than one call: analyze ten thousand rows, move forty thousand files, write to a hundred records. |
| [ConnectionsService](./connections.md) | Connect an account on behalf of one of your users, read the state of one, and disconnect it. |
| [KeysService](./keys.md) | The project's own API keys: mint one, list them, retire one. |
| [TriggersService](./triggers.md) | The inbound direction: an external app has something happen, and you hear about it. |
| [TracesService](./traces.md) | Read back one decision and everything that ran under it. |
| [UsageService](./usage.md) | What this project has used, aggregated from the same receipts everything else reads. |

This list is a reviewed one. atmon runs more services than these, and the rest are how the product is operated rather than an interface you build against, so they are not documented here and are not part of what we keep stable for you.
