Docs / Rates Data API / Endpoints / List exchange rates
List exchange rates
Returns one row per (date, code), newest ingest first. `date` is the calendar date you asked about in Asia/Baku; `effective_date` is the date the bank says those rates take effect from, read out of the bulletin rather than inferred from the date requested. Filter `carried_forward=false` for a strict business-day series, or take every row for a dense daily one and know which values are repeats.
Query parameters
| Parameter | Type | Description |
|---|---|---|
from |
date | Earliest `date`, inclusive. |
to |
date | Latest `date`, inclusive. |
codes |
string | Currency or metal codes, comma-separated — `USD,EUR`. Case is normalised, and a repeated `?codes=` is unioned with the list rather than overwriting it. Omit for all 42. |
kind |
string | `currency` or `metal`. The metals are the four the bank publishes per troy ounce. |
carried_forward |
boolean | `false` returns only the dates the bank actually published on — a strict business-day series. `true` returns only the repeats. Omit for the dense daily series, which is both. |
limit |
integer | Items per page, 1–100. Defaults to 25. |
cursor |
string | Opaque cursor from a previous response's meta.next. Do not construct one. |
order |
string | Sort field: `ingested_at`, each optionally prefixed with `-` to reverse. Default is `-ingested_at`. Rows with no value for the sort column always sort LAST in either direction, so paging never leads with undated rows. |
source |
string | Restrict to ONE scraper source, by its stem — `abb`, not `ABB` or `abb-bank.az`. Not a list: `?source=a,b` and a repeated `?source=` do not select two sources. On `/v1/jobs` an unknown stem is a `400` naming it, and `source_type` is the way to select several sources at once. `GET /v1/sources` lists every stem. |
Request
curl -G https://api.softon.dev/v1/rates \
-H "Authorization: Bearer $SOFTON_KEY" \
-d from=2026-09-01 -d to=2026-09-05 -d codes=USD,EUR
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.softon.dev/v1/rates", nil) req.Header.Set("Authorization", "Bearer "+os.Getenv("SOFTON_KEY")) q := req.URL.Query() q.Set("from", "2026-09-01") q.Set("to", "2026-09-05") q.Set("codes", "USD,EUR") req.URL.RawQuery = q.Encode() res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() var page struct { Data []Rate `json:"data"` Meta struct{ Next *string `json:"next"` } `json:"meta"` } if err := json.NewDecoder(res.Body).Decode(&page); err != nil { log.Fatal(err) } // page.Meta.Next → send it back as ?cursor= for the following page
import json, os, urllib.parse, urllib.request url = "https://api.softon.dev/v1/rates" + "?" + urllib.parse.urlencode({ "from": "2026-09-01", "to": "2026-09-05", "codes": "USD,EUR", }) req = urllib.request.Request(url, headers={ "Authorization": "Bearer " + os.environ["SOFTON_KEY"], }) page = json.load(urllib.request.urlopen(req)) # page["meta"]["next"] → send it back as ?cursor= for the following page
const url = new URL("https://api.softon.dev/v1/rates"); url.searchParams.set("from", "2026-09-01"); url.searchParams.set("to", "2026-09-05"); url.searchParams.set("codes", "USD,EUR"); const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.SOFTON_KEY}` }, }); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); const { data, meta } = await res.json(); // meta.next → send it back as ?cursor= for the following page
Response
The envelope is identical on every softon.dev API: data, meta, error. Only the shape inside data changes per dataset — see the response envelope.
{
"data": [
{
"id": "cbar:2026-09-05:USD",
"source": "cbar",
"date": "2026-09-05",
"effective_date": "2026-09-04",
"carried_forward": true,
"kind": "currency",
"base": "AZN",
"code": "USD",
"name": "1 AB\u015e dollar\u0131",
"unit": "unit",
"nominal": 1,
"value": 1.7,
"rate_per_unit": 1.7,
"source_url": "https://www.cbar.az/currencies/05.09.2026.xml",
"bulletin_url": "https://www.cbar.az/currencies/04.09.2026.xml",
"ingested_at": "2026-09-14T22:53:47.016591Z"
}
],
"meta": { "count": 1, "next": "eyJvIjoyfQ", "request_id": "req_9Fv3" },
"error": null
}
Fields of each item in data[]
| Field | Type | Description |
|---|---|---|
id |
string | Stable identifier, "<source>:<date>:<code>" — `cbar:2026-09-05:USD`. Opaque: treat the whole string as the id rather than parsing the halves out of it. |
source |
string | Which scraper delivered this bulletin. `cbar` is the Central Bank of Azerbaijan. |
date |
date | The calendar date this row answers for, **Asia/Baku**. Azerbaijan is UTC+4 year-round with no DST, so a consumer computing "today" in UTC gets yesterday's date for the four hours after 20:00 Baku — which is a real bug this feed's predecessor shipped, not a hypothetical one. |
effective_date |
date | The date the bank says these rates take effect from — the bulletin's own `ValCurs Date=`, never inferred from the date requested. On a business day it equals `date`; on a weekend, a public holiday or a future date it is the last business day before it. |
carried_forward |
boolean | `date != effective_date`: these numbers were published earlier and are still standing. **Filter `carried_forward=false` for a strict business-day series**; take every row for a dense daily one and know which values are repeats. The upstream answers `200` with a full bulletin for every date string including weekends and dates in the future, so this flag is the only thing that distinguishes a fresh publication from a repeat. |
kind |
string | `currency` or `metal`. The four bank metals (XAU, XPD, XPT, XAG) are the metals. |
base |
string | The currency the rate is expressed in. Always `AZN` for this source. |
code |
string | ISO 4217 code, or the metal's X-code. 42 per bulletin: 38 currencies and 4 bank metals. `SDR` is the IMF basket rather than a currency, and is carried as the bank publishes it. |
name |
string · nullable | The bank's own label, in Azerbaijani, including the multiplier it prints there — "1 ABŞ dolları", "100 Yapon iyeni". |
unit |
string | What one of `nominal` is: `unit` for a currency, `troy_ounce` for a metal. |
nominal |
integer | How many units `value` is quoted for. Seven currencies quote per 100 — KRW, KZT, HUF, UZS, PKR, RUB and JPY — and everything else per 1. Reading `value` without dividing by this is how a rouble comes out a hundred times too large. |
value |
number | The published figure, unrounded: AZN per `nominal` units. |
rate_per_unit |
number | `value / nominal`, unrounded. **This is the number you almost certainly want**: AZN for one unit of `code`, or for one troy ounce of a metal. |
source_url |
string · nullable | The document requested for `date`. |
bulletin_url |
string · nullable | The document these numbers were published in, i.e. the one for `effective_date`. Differs from `source_url` on a carried-forward row. |
ingested_at |
timestamp | When this version was stored. |
Try it
Send the request to see a response.