---
title: "Agent payments"
description: "Agent-created accounts funded with USDC or any Solana token."
canonical_url: "https://minirouter.sh/docs/agent-payments"
markdown_url: "https://minirouter.sh/docs/agent-payments.md"
last_updated: "2026-09-26"
---

# Agent payments

An agent creates its own account and pays with Solana USDC or any Solana token.

## How it works

*JUP, SOL, MINI or any Solana token converts to USDC and lands as the agent's credit.*

1. **Sign up**: One POST returns a key and a deposit address.
2. **Pay**: Send USDC, or swap any Solana token into it.
3. **Spend**: Call any paid model once credit lands.

## Prerequisites

- A Solana wallet holding USDC or the token you pay with.
- SOL in that wallet for network fees.
- Node.js 20 or later with `@solana/web3.js` for the TypeScript examples.

## Pay with USDC

No swap. USDC credits one for one.

### 1. Create an account

No body. Save the key; it is shown once.

**cURL**

```sh
curl -X POST https://api.minirouter.sh/accounts/agent
```

**TypeScript**

```ts
const signup = await fetch("https://api.minirouter.sh/accounts/agent", { method: "POST" })
  .then((res) => res.json());

const key = signup.key.key;
const address = signup.depositProvisioning.address;
```

### 2. Send USDC

Send at least $0.50 of Solana USDC to `depositProvisioning.address`.

```sh
spl-token transfer --fund-recipient \
  EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v 5 <depositProvisioning.address>
```

### 3. Check the balance

`availableNano` turns positive once the payment finalizes.

**cURL**

```sh
curl https://api.minirouter.sh/balance \
  -H "Authorization: Bearer $MINIROUTER_KEY"
```

**TypeScript**

```ts
const balance = await fetch("https://api.minirouter.sh/balance", {
  headers: { Authorization: `Bearer ${key}` },
}).then((res) => res.json());

console.log(balance.availableUsd);
```

## Pay with any Solana token

Any token Jupiter can price converts to USDC in one transaction. Credit is the USDC that lands.

### 1. Create an account

No body. Save the key; it is shown once.

**cURL**

```sh
curl -X POST https://api.minirouter.sh/accounts/agent
```

**TypeScript**

```ts
const signup = await fetch("https://api.minirouter.sh/accounts/agent", { method: "POST" })
  .then((res) => res.json());

const key = signup.key.key;
const address = signup.depositProvisioning.address;
```

### 2. Quote

`inputAmount` is in whole tokens. `minimumNano` is the least credit you receive.

```sh
curl https://api.minirouter.sh/deposits/solana-wallet/quote \
  -H "Authorization: Bearer $MINIROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"inputMint":"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN","inputAmount":"20"}'
```

### 3. Create an intent

Set `requestedNano` to the quote's `minimumNano`.

```sh
curl https://api.minirouter.sh/deposits/intents \
  -H "Authorization: Bearer $MINIROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rail":"solana-usdc","requestedNano":"<minimumNano>","idempotencyKey":"<uuid>"}'
```

### 4. Build the swap

Returns an unsigned transaction that pays your deposit address.

```sh
curl https://api.minirouter.sh/deposits/solana-wallet/order \
  -H "Authorization: Bearer $MINIROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"intentId":"<intentId>","wallet":"<public key>","inputMint":"JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN","inputAmount":"20"}'
```

### 5. Sign and execute

```ts
import { VersionedTransaction } from "@solana/web3.js";

const tx = VersionedTransaction.deserialize(Buffer.from(order.transaction, "base64"));
tx.sign([wallet]);
const signedTransaction = Buffer.from(tx.serialize()).toString("base64");
```

```sh
curl https://api.minirouter.sh/deposits/solana-wallet/execute \
  -H "Authorization: Bearer $MINIROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"intentId":"<intentId>","requestId":"<requestId>","signedTransaction":"<base64>","lastValidBlockHeight":"<height>"}'
```

### 6. Check the balance

`availableNano` turns positive once the payment finalizes.

**cURL**

```sh
curl https://api.minirouter.sh/balance \
  -H "Authorization: Bearer $MINIROUTER_KEY"
```

**TypeScript**

```ts
const balance = await fetch("https://api.minirouter.sh/balance", {
  headers: { Authorization: `Bearer ${key}` },
}).then((res) => res.json());

console.log(balance.availableUsd);
```

> **Warning:** Pass the exact mint address. Tickers are not unique.

## Full example

Signup, JUP swap, balance wait and a first paid request. Run with `npx tsx agent-e2e.ts`.

> **Warning:** This signs a real mainnet swap of `INPUT_AMOUNT` JUP, 20 by default.

```ts
import { Keypair, VersionedTransaction } from "@solana/web3.js";

const api = "https://api.minirouter.sh";
const inputMint = "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN";
const inputAmount = process.env.INPUT_AMOUNT ?? "20";
const wallet = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(process.env.SOLANA_SECRET_KEY!)));

const signup = await fetch(`${api}/accounts/agent`, { method: "POST" }).then((res) => res.json());
const key: string = signup.key.key;
console.log("Save these:", key, `https://minirouter.sh${signup.accessPath}`);

const call = async (path: string, body?: unknown) => {
  const res = await fetch(api + path, {
    method: body === undefined ? "GET" : "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    ...(body === undefined ? {} : { body: JSON.stringify(body) }),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
};

const quote = await call("/deposits/solana-wallet/quote", { inputMint, inputAmount });
const intent = await call("/deposits/intents", {
  rail: "solana-usdc",
  requestedNano: quote.minimumNano,
  idempotencyKey: crypto.randomUUID(),
});
const order = await call("/deposits/solana-wallet/order", {
  intentId: intent.intentId,
  wallet: wallet.publicKey.toBase58(),
  inputMint,
  inputAmount,
});
const tx = VersionedTransaction.deserialize(Buffer.from(order.transaction, "base64"));
tx.sign([wallet]);
await call("/deposits/solana-wallet/execute", {
  intentId: intent.intentId,
  requestId: order.requestId,
  signedTransaction: Buffer.from(tx.serialize()).toString("base64"),
  lastValidBlockHeight: order.lastValidBlockHeight,
});

let balance = await call("/balance");
for (let tries = 0; BigInt(balance.availableNano) === 0n && tries < 60; tries += 1) {
  await new Promise((resolve) => setTimeout(resolve, 5_000));
  balance = await call("/balance");
}
console.log("Credit:", balance.availableUsd);

const reply = await call("/v1/chat/completions", {
  model: "minirouter/auto",
  messages: [{ role: "user", content: "Say hi from an agent that paid in JUP." }],
  max_tokens: 64,
});
console.log(reply.choices[0].message.content);
```

## API reference

Base URL `https://api.minirouter.sh`.

### Create an account

| Endpoint | Auth |
| --- | --- |
| `POST /accounts/agent` | Auth: none |

### Request

No body.

### Response

| Field | Description |
| --- | --- |
| `accountId` | `string` Account ID. |
| `key.key` | `string` API key. Shown once. |
| `key.dailyLimitNano` | `string` Daily spend cap in nano-USD. Default $25. |
| `accessToken` | `string` Dashboard access token. Shown once. |
| `accessPath` | `string` Append to https://minirouter.sh to open the dashboard. |
| `depositProvisioning.status` | `string` `ready`, `pending` or `unconfigured`. |
| `depositProvisioning.address` | `string` Solana deposit address, when ready. |

### Quote

| Endpoint | Auth |
| --- | --- |
| `POST /deposits/solana-wallet/quote` | Auth: [Bearer API key](https://minirouter.sh/docs/authentication) |

### Request

| Field | Description |
| --- | --- |
| `inputMint` | `string` Token mint address. |
| `inputAmount` | `string` Whole tokens. |

### Response

| Field | Description |
| --- | --- |
| `inputSymbol` | `string` Token symbol. |
| `inputAmount` | `string` Amount in base units. |
| `expectedNano` | `string` Expected credit in nano-USD. |
| `minimumNano` | `string` Least credit you receive. |
| `meetsMinimum` | `boolean` Whether it clears the $0.50 minimum. |

### Create an intent

| Endpoint | Auth |
| --- | --- |
| `POST /deposits/intents` | Auth: [Bearer API key](https://minirouter.sh/docs/authentication) |

### Request

| Field | Description |
| --- | --- |
| `rail` | `string` `solana-usdc`. |
| `requestedNano` | `string` The quote's `minimumNano`. |
| `idempotencyKey` | `string` Unique per payment. Retries return the same intent. |

### Response

| Field | Description |
| --- | --- |
| `intentId` | `string` Pass to order and execute. |
| `stage` | `string` `created`, `waiting`, `detected`, `confirming`, then `settled`. |
| `payTo` | `string` The account's deposit address. |

### Build the swap

| Endpoint | Auth |
| --- | --- |
| `POST /deposits/solana-wallet/order` | Auth: [Bearer API key](https://minirouter.sh/docs/authentication) |

### Request

| Field | Description |
| --- | --- |
| `intentId` | `string` From the intent. |
| `wallet` | `string` Paying wallet's public key. |
| `inputMint` | `string` Same as the quote. |
| `inputAmount` | `string` Same as the quote. |

### Response

| Field | Description |
| --- | --- |
| `requestId` | `string` Pass to execute. |
| `transaction` | `string` Unsigned versioned transaction, base64. |
| `lastValidBlockHeight` | `string` Pass to execute. |
| `minimumUsdcMicros` | `string` Least USDC that lands, in micro-USDC. |
| `expiresAt` | `string` Execute before this time. |

### Execute

| Endpoint | Auth |
| --- | --- |
| `POST /deposits/solana-wallet/execute` | Auth: [Bearer API key](https://minirouter.sh/docs/authentication) |

### Request

| Field | Description |
| --- | --- |
| `intentId` | `string` From the intent. |
| `requestId` | `string` From the order. |
| `signedTransaction` | `string` Signed transaction, base64. |
| `lastValidBlockHeight` | `string` From the order. Optional. |

### Response

| Field | Description |
| --- | --- |
| `status` | `string` `Success`. Failures return an error. |
| `signature` | `string` Solana transaction signature. |
| `outputUsdcMicros` | `string` USDC delivered, in micro-USDC. |

### Check the balance

| Endpoint | Auth |
| --- | --- |
| `GET /balance` | Auth: [Bearer API key](https://minirouter.sh/docs/authentication) |

### Request

No body.

### Response

| Field | Description |
| --- | --- |
| `availableNano` | `string` Spendable credit in nano-USD. |
| `availableUsd` | `string` The same, in USD. |
| `reservedNano` | `string` Held for requests in flight. |

## Limits

| Limit | Value |
| --- | --- |
| Signups | 5 per IP per hour. |
| Key spend | $25 per day until raised in [key limits](https://minirouter.sh/docs/authentication#per-key-controls). |
| Minimum payment | $0.50. |
| Quotes | 30 per minute per account. |
| Orders and executes | 10 per minute each, per account. |
| Auto Free and chat trial | Not available, even after [claiming](https://minirouter.sh/docs/authentication#claim-an-account-later). |

## Errors

| Status | When |
| --- | --- |
| `400 invalid_request` | Unknown, unpriced or suspicious mint; USDC sent to the swap; wallet lacks the token or SOL. |
| `403 forbidden` | Auto Free or the chat trial on an agent account. |
| `429 rate_limited` | A limit above. Wait for `Retry-After`. |
| `503 payment_unavailable` | Jupiter or the Solana RPC is unreachable. Retry. |

## More resources

- [Authentication](https://minirouter.sh/docs/authentication): Rotate keys and raise limits.
- [Billing](https://minirouter.sh/docs/billing): Credits, holds and minimums.
- [Models](https://minirouter.sh/docs/models): Every model an agent can call.
- [Errors](https://minirouter.sh/docs/errors): Every error code and its fix.
