Wallet
Read your Proxio wallet balance with GET /wallet, fund it with POST /wallet/topups (a 201 is a payment link, not money), and page through the transaction ledger with GET /wallet/transactions, filterable by type and date range, sortable by created_at or amount.
Your wallet is the balance that pays for orders and renewals. These endpoints read the current balance, fund it, and read the full transaction ledger.
Scope: read to read the balance, transactions, and top-ups; purchase
to open a top-up.
Balance
GET /wallet returns the current balance.
curl https://dashboard.proxio.net/api/v1/wallet \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"import requests
BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
resp = requests.get(
f"{BASE}/wallet",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=15,
)
resp.raise_for_status()
print(resp.json()["data"]["balance"])const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const res = await fetch(`${BASE}/wallet`, {
headers: { Authorization: `Bearer ${API_KEY}` },
})
console.log((await res.json()).data.balance)200 response:
{
"data": { "currency": "USD", "balance": "42.50" },
"meta": { "request_id": "req_8Ke2jP4mQ" }
}Top-ups
Funding a wallet from the API, so an unattended pipeline that hits
INSUFFICIENT_BALANCE can refill
itself instead of stopping dead.
Scope: purchase to create, read to list and read back.
A 201 here is a payment link, not money
Creating a top-up returns a provider-hosted payment link, it does not
take card details and it does not credit anything. meta.funded is
false on every creation response, always, for exactly this reason: a
201 means the link was minted, not that the balance moved. The balance
changes only when the payment provider confirms the payment, and
wallet.topup_completed is how
a pipeline learns it can spend, poll
GET /wallet/topups/{id} or subscribe to that event
rather than assuming a 201 means funded.
Top up the wallet
POST /wallet/topups opens a hosted checkout. Requires the purchase scope
and a required Idempotency-Key (same requirement as
POST /orders): retrying with the same key
returns the identical link rather than opening a second one.
Body
| Field | Type | Notes |
|---|---|---|
amount | number | Required. 1 to 10,000 USD on this endpoint (the dashboard's own top-up form allows a wider range, this is the API's own ceiling). |
currency | string | Optional. USD is the only supported value today; anything else fails validation. |
payment_method | string | Optional. card or crypto. Omit it to let Proxio pick (card first, then crypto) from what's currently available. |
curl -X POST https://dashboard.proxio.net/api/v1/wallet/topups \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "amount": 25, "payment_method": "card" }'import uuid
import requests
BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
resp = requests.post(
f"{BASE}/wallet/topups",
headers={
"Authorization": f"Bearer {API_KEY}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"amount": 25, "payment_method": "card"},
timeout=15,
)
resp.raise_for_status()
topup = resp.json()["data"]
print(topup["payment_url"]) # open this, it's not returned againimport { randomUUID } from "node:crypto"
const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const res = await fetch(`${BASE}/wallet/topups`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": randomUUID(),
},
body: JSON.stringify({ amount: 25, payment_method: "card" }),
})
const topup = (await res.json()).data
console.log(topup.payment_url) // open this, it's not returned again201 response:
{
"data": {
"id": "cltop_4n7q3x",
"status": "pending",
"amount": "25.00",
"currency": "USD",
"payment_method": "card",
"payment_url": "https://checkout.example.com/pay/cs_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aY",
"created_at": "2026-08-20T13:30:00.000Z"
},
"meta": { "funded": false, "request_id": "req_8Ke2jP4mQ" }
}payment_url is shown exactly once
Like the webhook signing secret and a
credential's password,
payment_url rides only this response. Neither
GET /wallet/topups nor
GET /wallet/topups/{id} ever include it again,
there's nowhere it's stored to resurrect it from. Keep the URL you get back,
or, if you lost the response before the customer paid, replay the create
with the same Idempotency-Key to get it
again rather than opening a second checkout.
A provider that refuses or times out opening the checkout returns
UPSTREAM_ERROR (502); the idempotency key
cannot be reused, so retry with a fresh one. No payment method currently available for
API top-ups returns SERVICE_UNAVAILABLE (503).
List top-ups
GET /wallet/topups returns your top-up history,
cursor-paginated, newest first. payment_url is
absent on every row here, see the callout above.
Query parameters
| Parameter | Values | Notes |
|---|---|---|
status | pending, completed, failed, refunded | Optional, case-insensitive. Any other value fails with VALIDATION_ERROR rather than being ignored, so an empty page means you have no top-ups in that state. |
limit, cursor | see Pagination |
curl "https://dashboard.proxio.net/api/v1/wallet/topups?status=completed&limit=20" \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"import requests
BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
resp = requests.get(
f"{BASE}/wallet/topups",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"status": "completed", "limit": 20},
timeout=15,
)
resp.raise_for_status()
print(resp.json()["data"])const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const res = await fetch(`${BASE}/wallet/topups?status=completed&limit=20`, {
headers: { Authorization: `Bearer ${API_KEY}` },
})
console.log((await res.json()).data){
"data": [
{
"id": "cltop_4n7q3x",
"status": "completed",
"amount": "25.00",
"currency": "USD",
"payment_method": "card",
"created_at": "2026-08-20T13:30:00.000Z"
}
],
"meta": { "next_cursor": null, "has_more": false, "request_id": "req_8Ke2jP4mQ" }
}status covers four states an unattended caller actually needs to branch on:
pending (opened, not yet resolved, this also covers a payment the provider
has authorized but not yet captured), completed (the balance moved),
failed (it won't complete, open a new one), and refunded.
Read back a top-up
GET /wallet/topups/{id} returns a single top-up, the same shape as a list
row (no payment_url). This is the endpoint an unattended pipeline polls
after creating a top-up, until status is completed.
curl https://dashboard.proxio.net/api/v1/wallet/topups/cltop_4n7q3x \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"import requests
BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
resp = requests.get(
f"{BASE}/wallet/topups/cltop_4n7q3x",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=15,
)
resp.raise_for_status()
print(resp.json()["data"]["status"])const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const res = await fetch(`${BASE}/wallet/topups/cltop_4n7q3x`, {
headers: { Authorization: `Bearer ${API_KEY}` },
})
console.log((await res.json()).data.status)A top-up id that isn't yours, or never existed, returns
NOT_FOUND.
Transactions
GET /wallet/transactions returns the ledger, newest first,
cursor-paginated.
Query parameters
| Parameter | Values | Default | Notes |
|---|---|---|---|
type | one or more of the transaction types below, comma-separated | - | e.g. type=DEBIT_ORDER or type=TOPUP,REFUND. An unrecognized value fails with VALIDATION_ERROR naming it. |
created_after, created_before | ISO 8601 timestamps | - | Both inclusive. An unparseable value, or a created_before earlier than created_after, fails validation. |
sort | created_at | amount | created_at | amount is signed, so order=desc reads largest credit first and order=asc reads largest debit first. |
order | asc | desc | desc | |
limit, cursor | see Pagination |
A cursor is tied to the sort it was issued under
Changing sort or order partway through a paginated walk invalidates the
cursor you're holding: the next page fails with
INVALID_CURSOR rather than silently
skipping or repeating rows. Restart from cursor-less page one under the
new sort/order instead of trying to resume. See
Pagination for why.
curl "https://dashboard.proxio.net/api/v1/wallet/transactions?limit=20" \
-H "Authorization: Bearer pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"import requests
BASE = "https://dashboard.proxio.net/api/v1"
API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
resp = requests.get(
f"{BASE}/wallet/transactions",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"limit": 20},
timeout=15,
)
resp.raise_for_status()
body = resp.json()
for txn in body["data"]:
print(txn["type"], txn["amount"], txn["balance_after"])
print("next:", body["meta"]["next_cursor"])const BASE = "https://dashboard.proxio.net/api/v1"
const API_KEY = "pxo_9fJ2kQ7xR4mN8pL1dW6vB3cH5tZ0aYqS7dK2mN9x"
const res = await fetch(`${BASE}/wallet/transactions?limit=20`, {
headers: { Authorization: `Bearer ${API_KEY}` },
})
const body = await res.json()
for (const txn of body.data) {
console.log(txn.type, txn.amount, txn.balance_after)
}
console.log("next:", body.meta.next_cursor)200 response:
{
"data": [
{
"id": "cltxn_5a1b",
"type": "DEBIT_ORDER",
"amount": "-12.50",
"balance_after": "42.50",
"related_order_id": "clord_9f2a",
"note": "Order clord_9f2a",
"created_at": "2026-07-16T10:00:00.000Z"
}
],
"meta": { "next_cursor": null, "has_more": false, "request_id": "req_8Ke2jP4mQ" }
}Transaction types
| Type | Meaning | Amount sign |
|---|---|---|
TOPUP | Funds added to the wallet. | Positive |
DEBIT_ORDER | An order or renewal charge. | Negative |
REFUND | Funds returned. | Positive |
ADJUSTMENT | A manual correction. | Positive or negative |
amount and balance_after are signed decimal strings. Parse them with a
decimal type; a DEBIT_ORDER links back to its order via related_order_id.
Related pages
Locations
Fetch Proxio's geo-targeting catalog with GET /locations, the country, state, and city codes you can target, in ISO 3166-1 alpha-2 / ISO 3166-2 / city-slug form. Cacheable for an hour, with ETag / If-None-Match support for a cheap 304 on an unchanged catalog.
Orders
List, quote, and place Proxio orders. GET /orders and /orders/{id} read your order history, POST /orders/quote prices one without buying it, POST /orders places a wallet-paid purchase, and POST /services/{id}/renew tops up or extends a service. Pricing is server-authoritative and both purchase writes require an idempotency key.

