Payments

# Buy credits from a wallet

An agent with a Solana wallet funds its own `gk_` key: the gateway returns an unsigned USDC transaction, the agent signs it, and a confirm call credits the key. No email, and the private key never leaves the agent.

**On this page**

- [1. Open a purchase](https://inference.dagon.so/docs/wallet-purchase#1-open-a-purchase)
- [2. Sign](https://inference.dagon.so/docs/wallet-purchase#2-sign)
- [3. Confirm](https://inference.dagon.so/docs/wallet-purchase#3-confirm)
- [Errors](https://inference.dagon.so/docs/wallet-purchase#errors)

## 1. Open a purchase

POST `/v1/credits/purchase`

curl

```curl
curl https://inference.dagon.so/v1/credits/purchase \
  -H "Authorization: Bearer $DAGON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount_usd": 20, "payer_wallet": "<base58 address>", "chain": "solana"}'
```

$5 to $1,000, whole cents. `chain` must be `solana`. The answer: `purchase_id`, `amount_total`, `currency` (`usdc`), `unsigned_transaction` (base64), `blockhash`, `last_valid_block_height`, `fee_sponsored`, `expires_at` and `confirm_url`.

## 2. Sign

Deserialize `unsigned_transaction` (for example `VersionedTransaction.deserialize` in `@solana/web3.js`) and sign it with the wallet as returned, without rebuilding it. Its blockhash expires about a minute after step 1; if it does, open a new purchase.

When `fee_sponsored` is `true`, do not send it: its fee payer is the payment service's, which adds its signature and sends the transaction at confirm. The wallet then needs USDC and no SOL. When `false`, the wallet is the fee payer: send the transaction yourself (it pays the network fee in SOL), then confirm with its signature.

## 3. Confirm

POST `/v1/credits/purchase/confirm`

curl

```curl
curl https://inference.dagon.so/v1/credits/purchase/confirm \
  -H "Authorization: Bearer $DAGON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"purchase_id": "<purchase_id>", "signed_transaction": "<base64 wallet-signed transaction>"}'
```

`signed_transaction` is the base64 wallet-signed transaction, required when `fee_sponsored` is `true`: the payment service checks it is exactly the prepared payment, adds the fee payer's signature and sends it. When `false`, send `signature` instead, the base58 signature of the transaction you sent.

`200 {"status": "credited", "credited_usd", "balance"}` once the payment is final (the call can take about 45 seconds). `202 {"status": "pending"}` means call again, with the same body, after `Retry-After`. `GET /v1/credits/purchase/:id` reports `open`, `credited`, `expired`, `refused` or `pending`.

Copy-and-paste TypeScript and Python scripts: [buy credits from an agent wallet](https://inference.dagon.so/buy-llm-credits-from-an-agent-wallet).

## Errors

| Answer | Meaning |
| --- | --- |
| `400 invalid_wallet` | `payer_wallet` is not a Solana address that can sign. |
| `400 unsupported_chain` | `chain` is not `solana`. |
| `400 invalid_amount`, `amount_out_of_range` | Not whole cents, or outside the bounds. |
| `400 payment_not_verified` | The signed transaction or signature is not a payment of this purchase: wrong amount, altered, failed, or already used. |
| `403 payment_refused` | The wallet is on the OFAC sanctions list. |
| `451 location_blocked` | The caller's location is not served. |
| `503 payments_unavailable` | Try again later. |

Last updated 2026-11-09

[Previous **Payments and USDC checkout**](https://inference.dagon.so/docs/payments) [Next **x402 pay per request**](https://inference.dagon.so/docs/x402)
