> To find and run AgentRouter tools, connect to https://mcp.agentrouter.to/. To search this documentation, use https://docs.agentrouter.to/_mcp/server. Append .md to a page URL for Markdown. For the documentation index, see https://docs.agentrouter.to/llms.txt.

# HTTP API

Use the HTTP API from servers, notebooks and any language. There is no SDK to install; the API is plain JSON over HTTPS, and the [API reference](/api-reference) lists every endpoint.

|          |                                                                              |
| -------- | ---------------------------------------------------------------------------- |
| Base URL | `https://api.agentrouter.to`                                                 |
| Auth     | `Authorization: Bearer <API key or OAuth access token>`                      |
| Content  | `application/json` request and response bodies                               |
| Money    | Decimal strings in USD, e.g. `"0.0035"`. Parse them as decimals, not floats. |
| Retries  | `Idempotency-Key` header on `POST /v1/invoke`                                |

Find, describe and the catalog work without a key. Everything else needs one.

## API keys

Create keys at [Settings → API](https://www.agentrouter.to/settings/api), with `agentrouter keys add <name>`, or `POST /v1/keys`. The dashboard shows a newly created key once. Default scopes are `read`, `invoke`, `topup`, `feedback` and `dispute`; add `manage` only for keys that create other keys or budgets. Give each server or job its own key and a [key budget](/concepts/budgets), and revoke keys you no longer use.

Keep keys in your secret store. Never put them in client-side code, URLs or logs.

## A complete call

```python
import json, os, urllib.request
from decimal import Decimal

API = "https://api.agentrouter.to"
KEY = os.environ["AGENTROUTER_API_KEY"]

def post(path, body, headers=None):
    request = urllib.request.Request(API + path, data=json.dumps(body).encode(), method="POST",
        headers={"Content-Type": "application/json", "Authorization": f"Bearer {KEY}", **(headers or {})})
    try:
        with urllib.request.urlopen(request) as response:
            return response.status, json.load(response)
    except urllib.error.HTTPError as error:
        return error.code, json.load(error)

_, tool = post("/v1/describe", {"tool_id": "search1api.search"})
status, run = post("/v1/invoke", {
    "tool_id": "search1api.search",
    "pricing_version": tool["pricing"]["pricing_version"],
    "input": {"query": "agent tool marketplaces pricing", "max_results": 5},
    "max_cost_usd": "0.01",
}, headers={"Idempotency-Key": "job-118-search-1"})

print(status, run["status"], Decimal(run["billing"]["customer_charge_usd"]), run["billing"]["reason"])
```

## Handling responses

| HTTP | Body                                                 | Do                                                                           |
| ---- | ---------------------------------------------------- | ---------------------------------------------------------------------------- |
| 200  | Run, finished                                        | Read `status`, `output` (or `result.url`) and `billing`                      |
| 202  | Run, still running                                   | `GET /v1/runs/{run_id}?wait_ms=30000` until it finishes; do not invoke again |
| 402  | Run, `BLOCKED` with `INSUFFICIENT_BALANCE`           | Ask the user to top up                                                       |
| 409  | Run `BLOCKED`, or an error such as `PRICING_CHANGED` | Follow `hints`; describe again on price or version changes                   |
| 4xx  | Error envelope                                       | Fix the request; nothing ran                                                 |

See [Errors](/concepts/errors) for every code, and [Runs](/concepts/runs) for results, pagination and stopping.

## Scripts and CI without code

The [CLI](/integrations/cli) wraps the same API with `AGENTROUTER_API_KEY`, exit codes and `--json` output, and writes results to files with `--output`.