> For the complete documentation index, see [llms.txt](https://docs.vapinetwork.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vapinetwork.ai/reference/http-api/agents-and-router.md).

# Agents and Router

Agents and Router are coming soon; these HTTP routes describe owner links, controls, balances, and Router keys at launch.

{% hint style="info" %}
vAPI Router, Stake and Agents are coming soon. This page describes how they work at launch.
{% endhint %}

This page is for developers who need the HTTP routes behind agent links, owner controls, Router balance, and Router keys.

The `vapi` client and MCP server handle these flows for most users. See [Agents](https://docs.vapinetwork.ai/agents/) and the [CLI reference](/reference/cli-reference.md).

## Base URL

Use this base URL for every request on this page:

```
https://api.vapinetwork.ai
```

## Device grant

The device grant lets an agent prove control of its wallet, then wait for the owner to approve the link.

| Endpoint                           | Auth | Surface | Stability |
| ---------------------------------- | ---- | ------- | --------- |
| `POST /oauth/device_authorization` | none | all     | `beta`    |
| `POST /oauth/token`                | none | all     | `stable`  |

### POST /oauth/device\_authorization

Start the agent device grant with JSON or form data.

**Auth:** none.

| Request field          | Required | Description                                                                                            |
| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `agent_message`        | Yes      | EIP-4361 message bound to the API host and origin.                                                     |
| `agent_signature`      | Yes      | Agent wallet signature over `agent_message`.                                                           |
| `label`                | Yes      | 1 to 32 lowercase letters, digits, or hyphens. It must start with a letter or digit.                   |
| `device`               | No       | Device name using the same 1 to 32 character rule as `label`.                                          |
| `trust_device`         | No       | Boolean requesting approval through an owner-trusted device.                                           |
| `scope`                | No       | Space-separated subset of `mcp:call router.use call.publish`. Defaults to `mcp:call router.use`.       |
| `router_allowance_usd` | No       | Number from 0 to 1000 that suggests an initial allowance. The owner chooses the value during approval. |

Use the statement `Link this wallet to a vAPI account as an agent.` in the EIP-4361 message. Get its link-purpose nonce with `GET /api/auth/siwe-nonce?purpose=link`.

For automatic approval, send `device`, `trust_device=true`, and a bearer token for an account linked from that device. The owner must have trusted the device, and the token must cover the requested scopes. For `router.use`, supply `router_allowance_usd` within the trusted allowance. A successful automatic approval adds `auto_approved: true` to the response.

```bash
curl -X POST 'https://api.vapinetwork.ai/oauth/device_authorization' \
  -H 'Content-Type: application/json' \
  --data '{"agent_message":"<EIP-4361 message>","agent_signature":"<signature>","label":"weather-agent","scope":"mcp:call router.use","router_allowance_usd":25}'
```

A successful response contains the codes, approval URLs, polling interval, expiry, and agent client ID. Agent client IDs use the form `agent_<lowercase wallet>`.

```json
{
  "device_code": "<device code>",
  "user_code": "<user code>",
  "verification_uri": "<verification URI>",
  "verification_uri_complete": "<verification URI with code>",
  "expires_in": 1200,
  "interval": 5,
  "client_id": "agent_<lowercase wallet>"
}
```

| Status | Error                     | Meaning                                        |
| ------ | ------------------------- | ---------------------------------------------- |
| `400`  | `invalid_request`         | The request is invalid.                        |
| `400`  | `invalid_scope`           | The requested scope is not an allowed subset.  |
| `401`  | `invalid_agent_signature` | The agent signature is invalid.                |
| `503`  | `temporarily_unavailable` | The nonce or device-code store is unavailable. |

Error responses include `error_description`.

```json
{
  "error": "invalid_request",
  "error_description": "<description>"
}
```

### POST /oauth/token

Poll the token endpoint with the device grant form fields.

**Auth:** none.

| Form field    | Required | Description                                                   |
| ------------- | -------- | ------------------------------------------------------------- |
| `grant_type`  | Yes      | `urn:ietf:params:oauth:grant-type:device_code`                |
| `device_code` | Yes      | Code returned by the device authorization request.            |
| `client_id`   | Yes      | Agent client ID returned by the device authorization request. |

```bash
curl -X POST 'https://api.vapinetwork.ai/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
  --data-urlencode 'device_code=<device code>' \
  --data-urlencode 'client_id=agent_<lowercase wallet>'
```

After approval, the response contains the OAuth tokens, scopes, and owner wallet. It may also contain a vAPI Router key and base URL.

```json
{
  "access_token": "<access token>",
  "token_type": "<token type>",
  "expires_in": "<seconds>",
  "refresh_token": "<refresh token>",
  "scope": "mcp:call router.use",
  "owner_wallet": "0x1234567890abcdef1234567890abcdef12345678",
  "router_key": "<Router key>",
  "router_base_url": "<Router base URL>"
}
```

If the account link succeeds but Router key creation fails, the response omits `router_key` and `router_base_url` and adds this field:

```json
{
  "access_token": "<access token>",
  "token_type": "<token type>",
  "expires_in": "<seconds>",
  "refresh_token": "<refresh token>",
  "scope": "mcp:call router.use",
  "owner_wallet": "0x1234567890abcdef1234567890abcdef12345678",
  "router_key_error": "router_unavailable"
}
```

| Status        | Error                     | Meaning                          |
| ------------- | ------------------------- | -------------------------------- |
| `400`         | `authorization_pending`   | Device-grant polling error.      |
| `400`         | `slow_down`               | Device-grant polling error.      |
| `400`         | `access_denied`           | Device-grant polling error.      |
| `400`         | `expired_token`           | Device-grant polling error.      |
| Not specified | `invalid_request`         | Invalid input or client binding. |
| Not specified | `invalid_client`          | Invalid input or client binding. |
| Not specified | `invalid_grant`           | Invalid input or client binding. |
| `503`         | `temporarily_unavailable` | The device store is unavailable. |

The public contract does not specify status codes for `invalid_request`, `invalid_client`, or `invalid_grant` on this endpoint.

### Related OAuth endpoints

| Method    | Endpoint                                  | Auth    | Surface                   | Stability | Purpose                                                            |
| --------- | ----------------------------------------- | ------- | ------------------------- | --------- | ------------------------------------------------------------------ |
| GET       | `/.well-known/oauth-authorization-server` | none    | all                       | `stable`  | Authorization-server metadata.                                     |
| GET       | `/.well-known/oauth-protected-resource`   | none    | all                       | `stable`  | Protected-resource metadata.                                       |
| POST      | `/oauth/revoke`                           | none    | all                       | `stable`  | Token revocation.                                                  |
| POST      | `/oauth/register`                         | none    | `call`, `network`, `full` | `stable`  | Dynamic client registration.                                       |
| GET       | `/oauth/authorize`                        | session | `call`, `network`, `full` | `stable`  | Interactive consent page in HTML. It is guarded on other surfaces. |
| GET, POST | `/link`                                   | session | `call`, `network`, `full` | `beta`    | Agent approval page in HTML.                                       |

`/link` is the owner's approval page. An unsigned caller sees the sign-in prompt, and approval or denial requires the owner's session.

## Linked agents (owner session)

These routes require the owner's session. They are internal console endpoints that may change. Owner-session writes need a same-origin `Origin` header, such as `Origin: https://api.vapinetwork.ai`.

| Method | Endpoint                | Auth    | Surface                   | Stability  |
| ------ | ----------------------- | ------- | ------------------------- | ---------- |
| GET    | `/api/agents`           | session | `call`, `network`, `full` | `internal` |
| PATCH  | `/api/agents/:clientId` | session | `call`, `network`, `full` | `internal` |
| DELETE | `/api/agents/:clientId` | session | `call`, `network`, `full` | `internal` |

Owners can list, download, or delete their encrypted device backups.

| Method | Endpoint                             | Auth                       | Purpose                                          |
| ------ | ------------------------------------ | -------------------------- | ------------------------------------------------ |
| GET    | `/api/agents/backups`                | owner session              | List encrypted device backup metadata.           |
| GET    | `/api/agents/devices/:device/backup` | owner session              | Download the device's stored encrypted envelope. |
| DELETE | `/api/agents/devices/:device/backup` | owner session, same origin | Delete the device's stored encrypted envelope.   |

Each agent summary contains `clientId`, `wallet`, `label`, `scopes`, `linkedAt`, `lastUsedAt`, and `router`. The `router` value is `null` or contains `allowanceUsd` and `spentTodayUsd`.

### GET /api/agents

List the owner's live agent links.

**Auth:** session.

```bash
curl 'https://api.vapinetwork.ai/api/agents' \
  --cookie '<owner session>'
```

```json
{
  "agents": [
    {
      "clientId": "agent_0x1234567890abcdef1234567890abcdef12345678",
      "wallet": "0x1234567890abcdef1234567890abcdef12345678",
      "label": "weather-agent",
      "scopes": ["mcp:call", "router.use"],
      "linkedAt": "<timestamp>",
      "lastUsedAt": "<timestamp>",
      "router": {
        "allowanceUsd": "<USD amount>",
        "spentTodayUsd": "<USD amount>"
      }
    }
  ]
}
```

One owner may have at most 20 linked agents. Relinking an agent wallet to an owner revokes its previous live link.

### PATCH /api/agents/:clientId

Change an agent's Router allowance.

**Auth:** session.

| Path or body field   | Description            |
| -------------------- | ---------------------- |
| `clientId`           | Agent client ID.       |
| `routerAllowanceUsd` | Number from 0 to 1000. |

```bash
curl -X PATCH 'https://api.vapinetwork.ai/api/agents/agent_0x1234567890abcdef1234567890abcdef12345678' \
  --cookie '<owner session>' \
  -H 'Origin: https://api.vapinetwork.ai' \
  -H 'Content-Type: application/json' \
  --data '{"routerAllowanceUsd":25}'
```

The response wraps the updated agent summary in `agent`. An unknown client ID returns `404`.

```json
{
  "agent": {
    "clientId": "agent_0x1234567890abcdef1234567890abcdef12345678",
    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
    "label": "weather-agent",
    "scopes": ["mcp:call", "router.use"],
    "linkedAt": "<timestamp>",
    "lastUsedAt": "<timestamp>",
    "router": {
      "allowanceUsd": "<USD amount>",
      "spentTodayUsd": "<USD amount>"
    }
  }
}
```

### DELETE /api/agents/:clientId

Revoke the owner's tokens and vAPI Router keys for an agent. The request is idempotent.

**Auth:** session.

```bash
curl -X DELETE 'https://api.vapinetwork.ai/api/agents/agent_0x1234567890abcdef1234567890abcdef12345678' \
  -H 'Origin: https://api.vapinetwork.ai' \
  --cookie '<owner session>'
```

```http
HTTP/1.1 204 No Content
```

## Agent self endpoints (agent bearer)

These endpoints use an OAuth access token whose client ID starts with `agent_`.

| Method | Endpoint                              | Required scope  | Surface                   | Stability |
| ------ | ------------------------------------- | --------------- | ------------------------- | --------- |
| GET    | `/api/agents/self`                    | any agent scope | `call`, `network`, `full` | `beta`    |
| DELETE | `/api/agents/self`                    | None specified  | `call`, `network`, `full` | `beta`    |
| GET    | `/api/agents/self/router`             | `router.use`    | `call`, `network`, `full` | `beta`    |
| POST   | `/api/agents/self/router-key`         | `router.use`    | `call`, `network`, `full` | `beta`    |
| POST   | `/api/agents/self/router-balance-key` | `router.use`    | `call`, `network`, `full` | `beta`    |
| GET    | `/api/agents/self/stake`              | any agent scope | `call`, `network`, `full` | `beta`    |

Additional routes expose sibling accounts, encrypted backup uploads, backup relays, and signed transfers.

| Method | Endpoint                                 | Auth                          | Purpose                                                                               |
| ------ | ---------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------- |
| GET    | `/api/agents/self/siblings`              | agent bearer, any agent scope | Read the owner's sibling accounts, devices, status, allowances, and self marker.      |
| PUT    | `/api/agents/self/backup`                | agent bearer, any agent scope | Store the owner-encrypted envelope for the agent's device.                            |
| POST   | `/api/agents/backup-relays`              | none                          | Create a backup relay with a public key, code, device, and purpose.                   |
| GET    | `/api/agents/backup-relays/:code`        | owner session                 | Bind the relay to the owner and read its public key and metadata.                     |
| PUT    | `/api/agents/backup-relays/:code`        | owner session, same origin    | Upload the sealed result as the bound owner.                                          |
| GET    | `/api/agents/backup-relays/:code/result` | code capability               | Read the pending status or retrieve the sealed result once.                           |
| POST   | `/api/agents/relay-transfer`             | agent bearer, any agent scope | Relay an unchanged agent-signed USDC authorization to the owner or an active sibling. |

### GET /api/agents/self

Read the calling agent's link.

**Auth:** agent bearer with any agent scope.

```bash
curl -H 'Authorization: Bearer <agent access token>' \
  'https://api.vapinetwork.ai/api/agents/self'
```

```json
{
  "clientId": "agent_0x1234567890abcdef1234567890abcdef12345678",
  "wallet": "0x1234567890abcdef1234567890abcdef12345678",
  "owner": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
  "label": "weather-agent",
  "scopes": ["mcp:call", "router.use"],
  "linkedAt": "<timestamp>"
}
```

A revoked, expired, inactive, or non-agent credential receives `401` with `WWW-Authenticate`.

### DELETE /api/agents/self

Revoke the calling agent's link and vAPI Router keys.

**Auth:** agent bearer.

```bash
curl -X DELETE \
  -H 'Authorization: Bearer <agent access token>' \
  'https://api.vapinetwork.ai/api/agents/self'
```

```http
HTTP/1.1 204 No Content
```

Console API keys and non-agent OAuth clients receive `403`.

### GET /api/agents/self/router

Read the agent's daily Compute allowance and the owner's Router balance.

**Auth:** agent bearer with `router.use`.

```bash
curl -H 'Authorization: Bearer <agent access token>' \
  'https://api.vapinetwork.ai/api/agents/self/router'
```

```json
{
  "compute": {
    "allowanceUsd": "<USD amount>",
    "spentTodayUsd": "<USD amount>",
    "remainingTodayUsd": "<USD amount>",
    "resetsAt": "<timestamp>",
    "ownerLimitUsd": "<USD amount>",
    "ownerSpentUsd": "<USD amount>"
  },
  "balance": {
    "purchasedUsd": "<USD amount>",
    "spentUsd": "<USD amount>",
    "remainingUsd": "<USD amount>"
  }
}
```

`balance` is `null` when the owner has no Router balance.

### POST /api/agents/self/router-key

Mint a replacement vAPI Router key that keeps the agent's allowance. After minting, the endpoint deletes older non-top-up stake keys.

**Auth:** agent bearer with `router.use`.

```bash
curl -X POST \
  -H 'Authorization: Bearer <agent access token>' \
  'https://api.vapinetwork.ai/api/agents/self/router-key'
```

```json
{
  "router_key": "<Router key>",
  "router_base_url": "<Router base URL>"
}
```

### POST /api/agents/self/router-balance-key

Create the agent's balance key and remove its older balance keys.

**Auth:** agent bearer with `router.use`.

```bash
curl -X POST \
  -H 'Authorization: Bearer <agent access token>' \
  'https://api.vapinetwork.ai/api/agents/self/router-balance-key'
```

```json
{
  "router_key": "<Router key>",
  "router_base_url": "<Router base URL>"
}
```

### GET /api/agents/self/stake

Read the owner's stake and today's Compute amount for the agent.

**Auth:** agent bearer with any agent scope.

```bash
curl -H 'Authorization: Bearer <agent access token>' \
  'https://api.vapinetwork.ai/api/agents/self/stake'
```

```json
{
  "owner": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
  "epoch": "<epoch>",
  "stake": "<token amount in base units>",
  "computeTodayUsd": "<USD amount>",
  "stakeUrl": "<stake URL>"
}
```

The `stake` value is a decimal string in token base units.

## Router top-up

### POST /api/router/top-up/{1|5|20|50}

Buy the selected vAPI Router balance tier with exact USDC. An owner session, API key, or agent bearer may call this endpoint.

| Auth                                    | Surface                             | Stability |
| --------------------------------------- | ----------------------------------- | --------- |
| owner session, API key, or agent bearer | `call`, `router`, `network`, `full` | `beta`    |

| Path value              | Description                   |
| ----------------------- | ----------------------------- |
| `1`, `5`, `20`, or `50` | Router balance amount in USD. |

Send an authenticated request first. This example selects the 5 USD tier.

```bash
curl -i -X POST 'https://api.vapinetwork.ai/api/router/top-up/5' \
  -H 'Authorization: Bearer <API key or agent access token>'
```

Missing owner authentication returns `401` without a `PAYMENT-REQUIRED` header.

```json
{
  "error": "owner_required"
}
```

An authenticated unpaid request returns `402` with exact-USDC `accepts` entries for the configured networks. The payment is USDC on Base; Arc is included when that network is configured.

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "accepts": ["<exact USDC payment requirement>"]
}
```

After settlement, the selected tier returns `200` and includes the `PAYMENT-RESPONSE` header.

```http
HTTP/1.1 200 OK
PAYMENT-RESPONSE: <payment response>
Content-Type: application/json

{
  "status": "accepted",
  "usd": 5,
  "owner": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
}
```

See [x402 on vAPI](/reference/x402-on-vapi/x402.md) for the payment flow.

## Other Router endpoints

| Method    | Endpoint               | Auth    | Surface                     | Stability | Purpose                                                        |
| --------- | ---------------------- | ------- | --------------------------- | --------- | -------------------------------------------------------------- |
| GET, POST | `/api/router/keys`     | session | `router`, `network`, `full` | `beta`    | List or mint Router keys with a `compute` or `balance` source. |
| DELETE    | `/api/router/keys/:id` | session | `router`, `network`, `full` | `beta`    | Revoke one Router key.                                         |
| GET       | `/api/router/usage`    | session | `router`, `network`, `full` | `beta`    | Read epoch usage and Router balance totals.                    |
| GET       | `/api/router/models`   | none    | `router`, `network`, `full` | `beta`    | List available upstream models.                                |
| GET       | `/api/router/burns`    | none    | `router`, `network`, `full` | `beta`    | Read the Base mainnet buyback-burn ledger.                     |

Router keys default to 60 requests per minute, 100,000 tokens per minute, and 10 concurrent requests. An owner can have at most 10 Router keys. Key creation requires a label of 1 to 80 characters; `source` defaults to `compute` and also accepts `balance`.

## Next

* [Agents](https://docs.vapinetwork.ai/agents/)
* [CLI reference](/reference/cli-reference.md)
* [x402 on vAPI](/reference/x402-on-vapi/x402.md)

Checked on 2026-10-02.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.vapinetwork.ai/reference/http-api/agents-and-router.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
