myuiaf

AgentPay API

Call paid APIs per request from a prepaid wallet. For what AgentPay is and what it costs, see the AgentPay overview.

Base URL

https://agentpay.myuiaf.com

All responses from AgentPay itself are JSON. Responses from a route are passed through as the API sent them.

MCP server

https://agentpay.myuiaf.com/mcp

The same features as MCP tools (list_routes, call_route, wallet_balance and list_transactions), for Claude, OpenAI, Gemini, Grok and any MCP client. Streamable HTTP; send your key as Authorization: Bearer fv1.... Setup examples: Integrations.

Authentication

Use the same API key as Freshness Validator. It looks like fv1.<agent_id>.<key_id>.<secret>. Send it in any one of these headers:

X-Agent-API-Key: fv1.acme-bot.k1.xxxxx
X-Api-Key: fv1.acme-bot.k1.xxxxx
Authorization: Bearer fv1.acme-bot.k1.xxxxx

Use X-Agent-API-Key if the API you are calling needs its own Authorization header from you. Your key is never sent to the API. To get a key, buy a credit pack or see Buying credits. Repeated failed attempts are throttled by IP, across both services.

List routes

GET /v1/routes

The APIs you can call, with the price per successful call and the time limit.

{
  "routes": [
    {
      "id": "rt_weather",
      "name": "Weather",
      "description": "Forecasts by city",
      "pricing_model": "markup_5_percent",
      "price_per_call_usd": 0.03,
      "sla_ms": 800,
      "proxy_url": "https://agentpay.myuiaf.com/v1/proxy/rt_weather/"
    }
  ]
}

Call a route

ANY /v1/proxy/{route_id}/{path} GET, POST, PUT, PATCH, DELETE, HEAD

Everything after the route id, and the query string, is appended to the API's base URL. The method, body (up to 1 MB) and your other headers are forwarded. AgentPay adds the API's key and removes your key, cookies and proxy headers.

curl -X POST "https://agentpay.myuiaf.com/v1/proxy/rt_weather/forecast?units=metric" \
  -H "X-Agent-API-Key: fv1.acme-bot.k1.xxxxx" \
  -H "Idempotency-Key: 7f3c9a1e-forecast-honolulu" \
  -H "content-type: application/json" \
  -d '{"city":"Honolulu","days":3}'

Redirects from the API are returned to you, not followed, so the API key is never sent to another host.

Idempotency

Every call needs an Idempotency-Key header: 1 to 255 printable characters, unique for each logical call. A UUID works well. Keys are remembered for 24 hours.

You send a key thatResult
Is newThe call is made.
Already completedThe original response is returned again with Idempotent-Replayed: true. No new call, no new charge. Bodies over 64 KB are not kept: you get 409 replay_body_unavailable instead.
Is still in progress409 request_in_progress. Wait and retry.
Was used for a different request422 idempotency_key_reused. The method, path, query and body must match.
Failed before (not charged)The call is tried again.

When you are charged

The route's price is reserved from your available balance before the call, then:

What happenedYou getCharged
API answered 2xx within the time limitThe API's responseRoute price
API answered with any other statusThe API's response, as sentNothing
No full answer within the time limit504 sla_exceededNothing
API unreachable502 destination_unreachableNothing
Response larger than 10 MB502 response_too_largeNothing
Not enough available credit402 insufficient_credits, call not madeNothing
Wallet service unavailable503 ledger_unavailable, call not madeNothing

Money reserved for a call in progress is not available to other calls on either service until the call settles. A reservation that is never settled is released automatically, uncharged.

Response headers

HeaderMeaning
x-agentpay-call-idThe call's id in your transaction list
x-agentpay-charged-usdAmount charged for this call (0 if not charged)
x-agentpay-available-usdAvailable balance after the call
x-agentpay-ttfb-msTime until the API started answering
x-agentpay-total-msTotal time for the API's full answer
idempotent-replayedtrue on a replayed response

Balance

GET /v1/wallet/balance

{
  "agent_id": "acme-bot",
  "tier": "early_testing",
  "balance_usd": 4.97,
  "held_usd": 0.03,
  "available_usd": 4.94,
  "shared_with": "Freshness Validator (api.myuiaf.com)",
  "topup_url": "https://api.myuiaf.com/api/v1/credits"
}

held_usd is reserved for calls in progress. available_usd is what new calls can use.

Transactions

GET /v1/transactions ?limit=50&before=<call_id>

Your AgentPay calls, newest first, up to 200 per page. Pass next_before from one page as before to get the next.

{
  "transactions": [
    {
      "call_id": "001762570000000-a1b2c3",
      "idempotency_key": "7f3c9a1e-forecast-honolulu",
      "route_id": "rt_weather",
      "amount_usd": 0.03,
      "status": "completed",
      "reason": null,
      "destination_response_code": 200,
      "ttfb_ms": 171,
      "total_ms": 184,
      "ledger_tx_id": "...",
      "created_at": "2026-11-08T03:00:00.000Z",
      "settled_at": "2026-11-08T03:00:00.190Z"
    }
  ],
  "next_before": null,
  "next_url": null
}

status is completed (charged), failed (not charged; reason says why) or pending.

Buying credits

AgentPay uses your Freshness Validator wallet. People can buy a credit pack by card. Agents can buy their own credits with POST https://api.myuiaf.com/api/v1/credits, by card or in USDC: see Buying credits. A 402 from AgentPay includes the price of the call and this address.

Limits

LimitValue
Requests per minute60, 120, 300 or 1,000 by tier, counted separately from Freshness Validator
Request body1 MB
Response body10 MB
Replayed response kept64 KB, for 24 hours
Time limitSet per route (shown as sla_ms)

Errors

AgentPay's own errors look like this:

{ "error": "This call costs $0.03; the available wallet balance is $0.01", "code": "insufficient_credits",
  "price_usd": 0.03, "topup": { "url": "https://api.myuiaf.com/api/v1/credits", "method": "POST" } }
StatusCodeMeaning
400idempotency_key_requiredMissing or invalid Idempotency-Key
400invalid_pathThe path tries to leave the route
401missing_api_key, invalid_api_keyNo key, or a wrong or revoked key
402insufficient_creditsNot enough available credit for this call
404route_not_foundNo active route with this id
409request_in_progressSame key still running
409replay_body_unavailableCompleted call whose response was too large to keep
413body_too_largeRequest body over 1 MB
422idempotency_key_reusedSame key, different request
429rate_limited, temporarily_blockedToo many requests, or too many failed sign-ins; see Retry-After
502destination_unreachable, response_too_largeNot charged
503ledger_unavailable, routes_unavailable, route_misconfiguredTemporary; not charged. Retry with the same key.
504sla_exceededOver the route's time limit; not charged

Health

GET /v1/health

No key needed. Returns 200 with "status": "ok" when routes, keys and the wallet are all reachable, and 503 otherwise.