---
title: "How a request flows"
description: "What happens between an agent asking for an action and a landed transaction, and where each check happens."
editUrl: true
head: []
template: "doc"
sidebar: {"hidden":false,"attrs":{}}
pagefind: true
draft: false
---

> For the complete documentation index optimized for AI agents, see [llms.txt](https://docs.arete.run/llms.txt) or [llms-full.txt](https://docs.arete.run/llms-full.txt). A markdown version of this page is available at [/sandboxes/how-it-works.md](https://docs.arete.run/sandboxes/how-it-works.md) or by sending `Accept: text/markdown`.
An agent never builds, signs or sends a transaction itself. It names an
action and its arguments; Arete does the rest, and refuses anything your rules
don't allow before a signature exists.

```text
Agent (MCP tools / a4 CLI)
  │  its own API key mints a short-lived sandbox token
  │  (only while you grant it access; one scope per granted action)
  ▼
Arete sandbox API
  1. Grant check     is this action granted to this agent?
  2. Build           encode the named instructions from each program's IDL,
                     fill fixed, wallet and derived accounts
  3. Guard           every instruction and inner call against your rules:
                     programs, instructions, spend limits, destinations,
                     authority changes
  4. Trial run       simulate; a transaction that would fail is refused
  5. Sign and send   only now does the wallet's key sign
  6. Record          the action, its outcome, decoded events and balance changes
  ▼
Solana
```

## Authentication

The agent uses its own account's secret API key (`ARETE_API_KEY`, or its
`a4` login). With it, the MCP server lists the sandboxes the agent has been
granted and picks the one a call is for: the call's `sandbox` argument, else
the one chosen with `sandbox_select`, else the only active sandbox granted.
It then exchanges the key for a short-lived token for that one
sandbox. The exchange succeeds only while you grant that agent access, and the
token carries one scope per action you granted. When the token expires it is
minted again; when you revoke the grant, the next mint fails and the agent
stops.

Neither the API key nor the token is ever returned to the agent in a tool
result.

## Preview and invoke run the same checks

`sandbox_preview` runs steps 1 to 4 and stops: nothing is signed, sent or
recorded. It returns `pass` with what the wallet would lose
(`outflowLamports`, the network fee included) and the transaction it built,
or the refusal. `sandbox_invoke` runs every step.

Because both run the same checks, an agent can find out whether an action
passes, and what it costs, before committing to it.

## Exactly once

Every `sandbox_invoke` carries an idempotency key, the agent's own or a
generated one. A key never runs twice. If a call times out, the agent sends
the same request with the same key, which returns the original result
(`replayed: true`), or looks the action up with `sandbox_action`. A slow
network never turns into a double trade.

## Refusals

A refused action names the `code`, the `rule` that refused (such as
`program-allowlist`, `instruction-allowlist`, `outflow-cap` or
`session-grant`), what triggered it, whether the same request can succeed
later (`retryable`) and what to do (`hint`). Refusals are recorded in the
history too. See [Errors and refusals](/sandboxes/errors/).

## What the agent can see

Reads go through the same token: the wallet's status, the rules, holdings and
history. Program reads and live views are the sandbox's wider read surface,
scoped to the programs in its rules. See [Read scope](/sandboxes/read-scope/).
