ExecutionService
Run one tool, and read back what happened. Every call leaves a receipt, refusals included, and the receipt is what these calls return: the status, the result, and an error code that is empty on success. Nothing here throws when a call is refused; a refusal is an answer.
Every call is a POST to https://api.atmon.ai/automaton.v1.ExecutionService/<Call> with a JSON body, and authenticates with Authorization: Bearer <your project key>. Field names in JSON are lowerCamelCase, so the field written tool_slug below is toolSlug on the wire. How to call the API has the whole convention.
Calls
| Call | Request | Response | Summary |
|---|---|---|---|
ExecuteTool | ExecuteToolRequest | ExecuteToolResponse | Runs one tool for one entity, in a fixed order: resolution against the project's pinned catalog snapshot, mutation gate, policy gate, the resource lease, credential resolution, provider rate-limit pacing, the HTTP call (retried only for read tools), response shaping, then the ledger write. |
GetToolCall | GetToolCallRequest | GetToolCallResponse | Reads one ledger row by id. |
ListToolCalls | ListToolCallsRequest | ListToolCallsResponse | Lists an entity's ledger rows, newest first, optionally for one tool. |
ExecuteTool
Runs one tool for one entity, in a fixed order: resolution against the project's pinned catalog snapshot, mutation gate, policy gate, the resource lease, credential resolution, provider rate-limit pacing, the HTTP call (retried only for read tools), response shaping, then the ledger write. A refusal is a successful call whose ToolCall says it was refused, not an error: a gate is an answer. A denied or parked call resolves no credential and reaches no external app.
Request ExecuteToolRequest, response ExecuteToolResponse.
POST /automaton.v1.ExecutionService/ExecuteTool HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"entityId": "...",
"toolSlug": "...",
"argumentsJson": "{}",
"idempotencyKey": "...",
"resolutionId": "...",
"approvalId": "..."
}
The response:
{
"toolCall": {
"id": "...",
"entityId": "...",
"toolSlug": "...",
"connectedAccountId": "...",
"argumentsJson": "{}",
"status": "TOOL_CALL_STATUS_RUNNING",
"resultJson": "{}",
"errorCode": "...",
"errorDetail": "...",
"startedAt": "2026-01-31T09:15:00Z",
"finishedAt": "2026-01-31T09:15:00Z",
"approvalId": "...",
"resultTruncated": true,
"resourceUrn": "...",
"leaseWaitMs": 0,
"principalChain": ["..."],
"jobId": "...",
"stepId": "...",
"relayId": "..."
}
}
GetToolCall
Reads one ledger row by id.
Request GetToolCallRequest, response GetToolCallResponse.
POST /automaton.v1.ExecutionService/GetToolCall HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"id": "..."
}
The response:
{
"toolCall": {
"id": "...",
"entityId": "...",
"toolSlug": "...",
"connectedAccountId": "...",
"argumentsJson": "{}",
"status": "TOOL_CALL_STATUS_RUNNING",
"resultJson": "{}",
"errorCode": "...",
"errorDetail": "...",
"startedAt": "2026-01-31T09:15:00Z",
"finishedAt": "2026-01-31T09:15:00Z",
"approvalId": "...",
"resultTruncated": true,
"resourceUrn": "...",
"leaseWaitMs": 0,
"principalChain": ["..."],
"jobId": "...",
"stepId": "...",
"relayId": "..."
}
}
ListToolCalls
Lists an entity's ledger rows, newest first, optionally for one tool. Every outcome is a row: successes, failures, denials, and parked calls alike.
Request ListToolCallsRequest, response ListToolCallsResponse.
POST /automaton.v1.ExecutionService/ListToolCalls HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json
{
"entityId": "...",
"toolSlug": "...",
"pageSize": 0,
"pageToken": "...",
"principalChainPrefix": ["..."]
}
The response:
{
"toolCalls": [{
"id": "...",
"entityId": "...",
"toolSlug": "...",
"connectedAccountId": "...",
"argumentsJson": "{}",
"status": "TOOL_CALL_STATUS_RUNNING",
"resultJson": "{}",
"errorCode": "...",
"errorDetail": "...",
"startedAt": "2026-01-31T09:15:00Z",
"finishedAt": "2026-01-31T09:15:00Z",
"approvalId": "...",
"resultTruncated": true,
"resourceUrn": "...",
"leaseWaitMs": 0,
"principalChain": ["..."],
"jobId": "...",
"stepId": "...",
"relayId": "..."
}],
"nextPageToken": "..."
}
Messages
ExecuteToolRequest
| Field | Type | # | Notes |
|---|---|---|---|
entity_id | string | 1 | |
tool_slug | string | 2 | |
arguments_json | string | 3 | |
idempotency_key | string | 4 | same key returns the original call, not a rerun |
resolution_id | string | 5 | links the call to the router decision, if any |
approval_id | string | 6 | An approved policy approval, releasing a call that parked earlier. It is single use and only covers the same tool with the same arguments. |
ExecuteToolResponse
| Field | Type | # | Notes |
|---|---|---|---|
tool_call | ToolCall | 1 |
GetToolCallRequest
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 |
GetToolCallResponse
| Field | Type | # | Notes |
|---|---|---|---|
tool_call | ToolCall | 1 |
ListToolCallsRequest
| Field | Type | # | Notes |
|---|---|---|---|
entity_id | string | 1 | |
tool_slug | string | 2 | empty lists all tools |
page_size | int32 | 3 | |
page_token | string | 4 | |
principal_chain_prefix | repeated string | 140 | principal_chain_prefix lists every call whose chain opens with these hops, in this order: one key's effects, one skill's, one job's, one step's. It is as narrow a filter as entity_id and it crosses entities, because a job does, so a request carrying it may leave entity_id empty. A request carrying neither is refused. |
ListToolCallsResponse
| Field | Type | # | Notes |
|---|---|---|---|
tool_calls | repeated ToolCall | 1 | |
next_page_token | string | 2 |
ToolCall
| Field | Type | # | Notes |
|---|---|---|---|
id | string | 1 | |
entity_id | string | 2 | |
tool_slug | string | 3 | |
connected_account_id | string | 4 | |
arguments_json | string | 5 | |
status | ToolCallStatus | 6 | |
result_json | string | 7 | |
error_code | string | 8 | "rate_limited", "auth_expired", "invalid_arguments", ... |
error_detail | string | 9 | |
started_at | google.protobuf.Timestamp | 10 | |
finished_at | google.protobuf.Timestamp | 11 | |
approval_id | string | 12 | The policy approval this call waits on when status is PENDING_APPROVAL, or the approval the call was released by. Empty when no gate applied. |
result_truncated | bool | 13 | A shaping cap cut data the tool's output schema declared. The proto3 default carries the meaning that matters: absent means complete. |
resource_urn | string | 110 | The resource this call leased, rendered from the tool's lease_key rule (docs/toolkit-format.md, Resource leases). Empty when the tool declares no rule, which is most of the catalog. A call refused with resource_leased carries it too, so a contention names what it could not have. |
lease_wait_ms | int64 | 111 | How long taking that lease took, in milliseconds. Zero for a call that leased nothing. |
principal_chain | repeated string | 140 | Who ultimately caused this call, oldest cause first: "key:<id>", "skill:<slug>", "job:<id>", "step:<id>", "account:<id>". It is an audit record and never an authorization input. Empty for a row written before chains existed; those rows recorded no cause. |
job_id | string | 141 | The job step this call ran for, empty for a call made directly over the wire. Both are recorded by the engine and neither is ever read from a request: a caller-supplied job id would let one caller attribute its effects to another's job. |
step_id | string | 142 | |
relay_id | string | 150 | The on-prem relay that executed this call, empty for every call the platform sent itself. A row carrying it carries no connected_account_id: a relay call resolves none, because the credential it used never left the customer's network. |
Enums
ToolCallStatus
| Value | # | Meaning |
|---|---|---|
TOOL_CALL_STATUS_UNSPECIFIED | 0 | |
TOOL_CALL_STATUS_RUNNING | 1 | |
TOOL_CALL_STATUS_SUCCEEDED | 2 | |
TOOL_CALL_STATUS_FAILED | 3 | |
TOOL_CALL_STATUS_DENIED | 4 | blocked by policy before reaching the app |
TOOL_CALL_STATUS_PENDING_APPROVAL | 5 | parked on the policy approval gate |