Skip to Content
REST APICurrent rate

GET /v1/rates/{base}/{quote}

Reads the current exchange rate for a currency pair, either directly observed or derived from other pairs.

Need this over MCP instead? See get_rate →.

Auth

Authorization: ApiKey <key> — required.

Missing, invalid, or revoked key → 401 unauthorized:

{ "code": "unauthorized", "message": "A valid API key is required.", "request_id": "..." }

Path parameters

  • base, quote — trimmed, uppercased, must match ^[A-Z0-9]{2,10}$.

Invalid format → 400 invalid_asset_symbol (checked before billing):

{ "code": "invalid_asset_symbol", "message": "Asset symbol format is invalid.", "request_id": "..." }

Billing

Exactly one request unit is charged before the rate is read. If your account’s quota is already exhausted, the response is 429 with extra fields beyond the standard error envelope:

{ "code": "quota_exceeded", "message": "Request-unit quota exceeded for the current billing period.", "request_id": "...", "limit": 500, "remaining": 0, "reset_at": "2026-11-01T00:00:00Z" }

Success — 200

curl https://your-getratesapi-host/v1/rates/EUR/USD \ -H "Authorization: ApiKey gra_live_0000000000000000000000000000000000000000000000000000000000000000"
const res = await fetch("https://your-getratesapi-host/v1/rates/EUR/USD", { headers: { Authorization: "ApiKey gra_live_0000000000000000000000000000000000000000000000000000000000000000", }, }); const rate = await res.json();
{ "base": "EUR", "quote": "USD", "rate": "1.174582", "as_of": "2026-09-29T11:41:32.241582Z", "status": "fresh", "type": "direct" }
  • rate is an exact decimal string, never a JSON number.
  • as_of is RFC3339Nano UTC — the stored observation time, not the request time.
  • type is direct or derived (below).
  • status is fresh or stale (below).

Derived rates

Not every pair is quoted directly upstream. When no direct observation exists, the rate is computed, in this order:

  1. Identity — EUR/EUR is exactly 1.
  2. Direct — a stored observation for the pair.
  3. Reciprocal — the inverse of a stored quote/base observation.
  4. Pivot — two legs joined through USD, EUR, or BTC, in that order of preference.

Division is exact decimal division; results are not rounded to a fixed scale. A derived rate is marked "type": "derived" and its as_of is the oldest of its contributing observations — a chain is never fresher than its weakest link.

If no route exists, the response is 404 unsupported_pair.

Freshness

Crypto prices are refreshed from our providers every 10 seconds, fiat (including metals and XDR) every 60 seconds. status reports whether the underlying observation is recent, with a window that matches its feed:

Pairfreshstale
Both sides fiat (EUR/USD, XAU/CZK)observed within the last 5 minutesolder — still returned, but flagged
Any side crypto (BTC/USD, ETH/BTC)observed within the last minuteolder — still returned, but flagged

A derived rate is fresh only if every rate it was computed from is fresh under its own window — BTC→CZK via USD needs a fresh BTC/USD and a fresh USD/CZK.

A stale rate is served rather than withheld, because for most uses an hour-old rate is far better than no rate. Decide for yourself whether stale is acceptable for your use case; the service will not make that call for you.

Multiple quotes in one request

GET /v1/rates/{base}

Reads several quotes against one base in a single round trip. Pass up to 20 symbols in the quote parameter, either comma-separated or repeated:

curl "https://your-getratesapi-host/v1/rates/EUR?quote=USD,GBP,JPY" \ -H "Authorization: ApiKey gra_live_0000000000000000000000000000000000000000000000000000000000000000"
{ "base": "EUR", "rates": [ { "quote": "USD", "rate": "1.174582", "as_of": "...", "status": "fresh", "type": "direct" }, { "quote": "GBP", "rate": "0.868421", "as_of": "...", "status": "fresh", "type": "derived" } ], "unsupported": [ { "quote": "JPY", "code": "unsupported_pair", "message": "The requested currency pair is not currently supported." } ] }

A multi-quote request is one billable unit, regardless of how many quotes it carries. Quotes that cannot be served appear in unsupported[] rather than failing the whole request — one missing pair should not cost you the rest of your answer.

More than 20 quotes, or a malformed symbol anywhere in the list, is rejected with 400 before billing.

Other error outcomes

These happen after a successful charge — the unit is already consumed, with no refund:

StatusCodeMessage
404unsupported_pair“The requested currency pair is not currently supported.”
503temporarily_unavailable“The service is temporarily unable to serve this rate. Please retry.”

Any method other than GET/HEAD on this path returns 405 method_not_allowed.