> ## Documentation Index
> Fetch the complete documentation index at: https://docs.circuit.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Account Operations

> Base URL: https://api.circuit.org/v1

Circuit REST endpoints are grouped by resource: `/v1/{resource}/{operation}`. Account operation endpoints live under `/v1/operations/`.

Account operations let you create and manage reviewed money operations — swaps, sends, perp opens, and prediction orders — without any chat or UI surface. The lifecycle has two steps:

1. **Create** quotes your intent live and stores an inert operation in the `awaitingApproval` state. Creation never moves money.
2. **Approve** admits that exact reviewed operation for execution. Approval is the only step that moves money.

The passkey-derived bearer token from [authentication](../passkey-authentication) is the only credential these endpoints need — there is no separate API key or signing secret.

### Create Operation

Create a reviewed operation from a structured intent. The server resolves the wallet, obtains a live quote, and returns the operation in `awaitingApproval`. Nothing executes until you approve it.

**Endpoint:** `POST /v1/operations`

**Request**

| Header                          | Description                                        |
| ------------------------------- | -------------------------------------------------- |
| `Authorization: Bearer {token}` | User's API auth token acquired from authentication |

| Body             | Type     | Required | Description                                                                                                                                                                                                                         |
| ---------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `idempotencyKey` | `string` | true     | Client-generated UUID. Replaying the same key with an identical `operation` returns the same operation without re-quoting — the first captured review stays authoritative. The same key with a different `operation` returns `409`. |
| `operation`      | `object` | true     | The structured operation intent (below).                                                                                                                                                                                            |

The `operation` body is a discriminated union. Every arm names the paying/signing wallet by `walletId` from [`GET /v1/wallets/list`](./wallet-endpoints#list-user-wallets); the server verifies ownership and eligibility.

```typescript theme={null}
type StructuredOperationIntent =
  | { kind: "swap"; walletId: number; swapIntent: StructuredSwapIntent }
  | { kind: "send"; walletId: number; sendIntent: StructuredSendIntent }
  | { kind: "perp"; walletId: number; perpIntent: StructuredPerpIntent }
  | { kind: "perpClose"; walletId: number; closeIntent: StructuredPerpCloseIntent }
  | { kind: "prediction"; walletId: number; order: PolymarketOrder };

type StructuredSwapIntent = {
  // Token addresses; null means the network's native asset.
  from: { network: string; token: string | null };
  to: { network: string; token: string | null };
  // Human-unit decimal amount, or "max" — resolved from the live balance
  // at creation, never a client snapshot.
  amount: string;
  // The worst case you accept, in raw base units: the server refuses to
  // create the operation when the fresh quote's expected receive falls
  // below this rate, and enforces the same bar again at execution.
  quoteFloor: { sellRaw: string; receiveRaw: string };
  // Deliver to a different owned wallet. Absent = the paying wallet.
  toWalletId?: number;
};

type StructuredSendIntent = {
  token: { network: string; token: string | null };
  amount: string; // human-unit decimal, or "max"
  to: { walletId: number } | { address: string };
};

type StructuredPerpIntent = {
  coin: string; // venue-verbatim coin id
  side: "long" | "short";
  leverage?: number; // integer 1..100
  amountUsdc: string; // human-unit decimal, or "max"
};

type StructuredPerpCloseIntent = {
  coin: string; // venue-verbatim coin id; closes the whole live position
};
```

**cURL Example**

```bash theme={null}
curl -X POST "https://api.circuit.org/v1/operations" \
  -H "Authorization: Bearer api_auth_token" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "b3f1c0de-0000-4000-8000-000000000001",
    "operation": {
      "kind": "swap",
      "walletId": 456,
      "swapIntent": {
        "from": { "network": "ethereum", "token": null },
        "to": { "network": "ethereum", "token": "0xA0b8...eB48" },
        "amount": "0.5",
        "quoteFloor": { "sellRaw": "500000000000000000", "receiveRaw": "1200000000" }
      }
    }
  }'
```

**Response**

The operation resource, in `awaitingApproval`. Every operation endpoint returns this same shape.

```typescript theme={null}
{
  id: string;   // operation UUID — the one address for reads and decisions
  kind: string; // "action_sequence" for operations created here
  state: "awaitingApproval" | "working" | "done" | "dismissed"
    | "canceled" | "failed_before_effect" | "failed";
  // Per-leg execution progress; total is null until the plan is sized.
  progress: { legs: object[]; completed: number; total: number | null };
  // Explorer-linkable onchain transactions from recorded receipts.
  txs: object[];
  // Present when state is "done".
  result?: object;
  // Present in the failure states.
  error?: string;
  // The immutable stored request.
  request: {
    kind: "actionSequence";
    // The exact intent this operation was created from.
    creationRequest?: StructuredOperationIntent;
    // The reviewed, quoted actions captured at creation. Immutable:
    // replays never re-quote a captured operation.
    actions: object[];
  };
  // Compatibility provenance for existing chat callers. Headless operations
  // return null.
  source: { kind: string } | null;
}

```

List and read responses can also contain direct action and existing workflow operations. Direct Kraken actions omit their server-side `credentialRef`. Workflow requests expose only `{ kind: "workflow", operationKind }`; stored workflow payloads and credential references never cross the account interface.

Common errors: `400` when the intent fails validation or the wallet cannot fund it, `409` when the `idempotencyKey` was already used with a different request. See [API Errors](./api-errors).

### Get Operation

Read one operation. This is the canonical poll address: after approving, poll here until the state is terminal (`done`, `failed`, `failed_before_effect`, `canceled`, or `dismissed`).

**Endpoint:** `GET /v1/operations/{operationId}`

**Request**

| Header                          | Description                                        |
| ------------------------------- | -------------------------------------------------- |
| `Authorization: Bearer {token}` | User's API auth token acquired from authentication |

| Path Parameter | Description                                                                       |
| -------------- | --------------------------------------------------------------------------------- |
| `operationId`  | Operation UUID returned by [`POST /v1/operations`](./operations#create-operation) |

**cURL Example**

```bash theme={null}
curl -X GET "https://api.circuit.org/v1/operations/0198c2f1-8a4e-7000-8000-000000000001" \
  -H "Authorization: Bearer api_auth_token"
```

**Response**

The operation resource — the same shape as [Create Operation](./operations#create-operation). `404` when the operation does not exist or is not yours.

### Approve Operation

Admit an `awaitingApproval` operation for execution. This is the only endpoint that moves money. Re-approving the same operation converges on the same execution — it never runs twice.

**Endpoint:** `POST /v1/operations/{operationId}/approve`

**Request**

| Header                          | Description                                        |
| ------------------------------- | -------------------------------------------------- |
| `Authorization: Bearer {token}` | User's API auth token acquired from authentication |

| Path Parameter | Description                                                                       |
| -------------- | --------------------------------------------------------------------------------- |
| `operationId`  | Operation UUID returned by [`POST /v1/operations`](./operations#create-operation) |

**cURL Example**

```bash theme={null}
curl -X POST "https://api.circuit.org/v1/operations/0198c2f1-8a4e-7000-8000-000000000001/approve" \
  -H "Authorization: Bearer api_auth_token"
```

**Response**

The updated operation resource, normally in `working`. Repeating approval after admission, including after the operation becomes terminal, returns the current resource with `200`; it never executes twice. Poll [`GET /v1/operations/{operationId}`](./operations#get-operation) until terminal.

Errors: `400` when the operation does not use review approval or its pending source wallet is archived or missing, `404` when the operation does not exist, and `409` when a dismissed operation is no longer approvable.

### Discard Operation

Retire an `awaitingApproval` operation without executing it. Discarding is idempotent: repeating it returns the same `dismissed` resource.

**Endpoint:** `POST /v1/operations/{operationId}/discard`

**Request**

| Header                          | Description                                        |
| ------------------------------- | -------------------------------------------------- |
| `Authorization: Bearer {token}` | User's API auth token acquired from authentication |

| Path Parameter | Description                                                                       |
| -------------- | --------------------------------------------------------------------------------- |
| `operationId`  | Operation UUID returned by [`POST /v1/operations`](./operations#create-operation) |

**cURL Example**

```bash theme={null}
curl -X POST "https://api.circuit.org/v1/operations/0198c2f1-8a4e-7000-8000-000000000001/discard" \
  -H "Authorization: Bearer api_auth_token"
```

**Response**

The operation resource in `dismissed`. `409` when the operation already executed and can no longer be discarded.
