# Errors

TherosAI uses conventional HTTP status codes and a consistent JSON error format across all endpoints.

***

## Error object

All error responses follow this structure:

```json
{
  "error": {
    "code": "policy_violation",
    "message": "Transaction blocked by spending policy.",
    "docs": "https://docs.therosai.com/api-reference/errors#policy_violation",
    "request_id": "req_7f3b2a1c"
  }
}
```

Include the `request_id` when contacting support — it identifies the exact request in TherosAI's logs.

***

## HTTP status codes

| Code  | Meaning                                                                                              |
| ----- | ---------------------------------------------------------------------------------------------------- |
| `200` | Success                                                                                              |
| `400` | Bad request — invalid parameters or malformed JSON                                                   |
| `401` | Authentication failed — invalid or missing API key                                                   |
| `402` | Payment blocked — policy violation                                                                   |
| `403` | Forbidden — API key lacks required permissions                                                       |
| `404` | Resource not found                                                                                   |
| `409` | Conflict — duplicate idempotency key with different parameters                                       |
| `422` | Unprocessable — valid request but business logic prevented execution (e.g. insufficient org reserve) |
| `429` | Rate limited                                                                                         |
| `500` | Internal server error — TherosAI-side issue                                                          |

***

## Error codes

### Authentication

| Code                       | Description                                                                                     |
| -------------------------- | ----------------------------------------------------------------------------------------------- |
| `authentication_failed`    | Invalid or missing API key                                                                      |
| `insufficient_permissions` | API key lacks the required role for this operation                                              |
| `session_token_expired`    | The vault session authority token has expired. Rotate with `POST /v1/wallets/{id}/rotate-token` |
| `session_token_invalid`    | Session token does not match this vault                                                         |

### Wallets

| Code                          | Description                                                     |
| ----------------------------- | --------------------------------------------------------------- |
| `wallet_not_found`            | No vault with this ID in the organisation                       |
| `wallet_frozen`               | Vault is frozen — unfreeze before transacting                   |
| `wallet_insufficient_balance` | Vault USDC balance is insufficient for this payment             |
| `wallet_agent_id_conflict`    | An `agentId` with this value already exists in the organisation |

### Payments

| Code                   | Description                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------ |
| `policy_violation`     | Transaction blocked by spending policy. See `violation` field for the specific rule. |
| `invalid_recipient`    | Recipient address or domain is malformed or unresolvable                             |
| `invalid_amount`       | Amount is not a valid decimal string, is zero, or is negative                        |
| `idempotency_conflict` | Idempotency key already used with different parameters                               |

### Policies

| Code               | Description                                          |
| ------------------ | ---------------------------------------------------- |
| `policy_not_found` | No policy with this ID in the organisation           |
| `policy_immutable` | Preset policies cannot be modified. Clone first.     |
| `policy_in_use`    | Policy cannot be deleted — vaults are still attached |

### Organisation / Funding

| Code                         | Description                                                   |
| ---------------------------- | ------------------------------------------------------------- |
| `org_insufficient_balance`   | Organisation USDC reserve is insufficient for this allocation |
| `withdrawal_exceeds_balance` | Withdrawal amount exceeds the vault or org balance            |

### Escrow (A2A)

| Code                     | Description                                               |
| ------------------------ | --------------------------------------------------------- |
| `escrow_not_found`       | No escrow with this ID                                    |
| `escrow_expired`         | Escrow timeout has passed                                 |
| `escrow_already_settled` | Escrow has already been released, refunded, or disputed   |
| `invalid_proof`          | Completion proof format is invalid or hash does not match |

***

## Idempotency

Pass a unique `idempotencyKey` on payment requests to safely retry on network failure. If TherosAI receives a request with an idempotency key it has already processed successfully, it returns the original response rather than processing the request again.

If the same key is submitted with different parameters, `409 Conflict` is returned.

Idempotency keys expire after 24 hours.

***

## Handling errors in the SDK

```typescript
import { TherosAI, TherosAIError, PolicyViolationError } from "@TherosAI/sdk";

try {
  const tx = await wallet.pay({ to: "api.perplexity.ai", amount: "50.00", currency: "USDC" });
} catch (err) {
  if (err instanceof PolicyViolationError) {
    console.error("Blocked by policy:", err.violation);
    // { rule: "max_per_tx", limit: "5.00", attempted: "50.00" }
  } else if (err instanceof TherosAIError) {
    console.error("API error:", err.code, err.message);
  } else {
    throw err;
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.therosai.com/api-reference/errors.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
