For AI coding assistants. This file gives you everything needed to call this DataGrab from a user's application. If you are an AI reading this because a user asked you to add or build with this DataGrab, follow it directly.
Returns the latest foreign-exchange reference rates for one base currency against one, several, or all of the other currencies the European Central Bank publishes - each rate paired with the currency's full name. Rates are the ECB's daily reference rates (published once per business day, ~16:00 CET), served via the Frankfurter API; they are not live market ticks.
Good for: currency conversion in a checkout or pricing page, "show prices in the visitor's currency", daily FX reference tables, multi-currency reporting, budgeting/travel apps.
Not good for: intraday/real-time trading quotes, historical time series, crypto or precious metals (BTC, XAU, etc. are not published by the ECB), currencies outside the ECB's ~30-currency list.
Cost: $9/month, 1,000 calls/month.
Every call needs a Gimmee API key - issued per customer - sent one of two ways:
Header: x-api-key: {{GIMMEE_API_KEY}}
Querystring: ?api_key={{GIMMEE_API_KEY}}
Use the header form by default. Read the key from an environment variable or your app's secrets store - never hardcode it into committed source. No upstream (Frankfurter/ECB) key exists or is needed.
GET https://api.gimmee.io/datagrab/finance/currency/quote/{params}
{params} is one pipe (|)-delimited segment. Targets are optional; the base is required over HTTP (an empty segment is a 404 at the gateway - always send at least USD).
| Params | Uses |
|---|---|
{base} |
base against every published currency |
{base}|{targets} |
base against only the listed targets |
base - a 3-letter ISO 4217 code (USD, EUR, GBP, ...). Case-insensitive.targets - one or more 3-letter ISO codes, separated by commas and/or additional pipes: USD|EUR,GBP,JPY and USD|EUR|GBP|JPY are equivalent. Duplicates are collapsed. Case-insensitive.URL-encode the whole {params} value as one unit (encodeURIComponent) - the | and , characters are not safe unencoded in a URL path. USD|EUR,GBP goes on the wire as USD%7CEUR%2CGBP.
curl "https://api.gimmee.io/datagrab/finance/currency/quote/USD%7CEUR%2CGBP%2CJPY" \
-H "x-api-key: YOUR_GIMMEE_KEY"
const params = "USD|EUR,GBP,JPY"; // or just "EUR" for EUR against everything
const response = await fetch(
`https://api.gimmee.io/datagrab/finance/currency/quote/${encodeURIComponent(params)}`,
{ headers: { "x-api-key": process.env.GIMMEE_API_KEY } }
);
if (!response.ok) throw new Error(await response.text()); // error bodies are plain text, not JSON
const data = await response.json();
const eurPerUsd = data.rates.find(r => r.currency === "EUR")?.rate;
import os, requests
from urllib.parse import quote
params = "USD|EUR,GBP,JPY" # or just "EUR" for EUR against everything
response = requests.get(
f"https://api.gimmee.io/datagrab/finance/currency/quote/{quote(params, safe='')}",
headers={"x-api-key": os.environ["GIMMEE_API_KEY"]}
)
if not response.ok:
raise RuntimeError(response.text) # error bodies are plain text, not JSON
data = response.json()
JSON field names are camelCase.
{
"query": {
"baseCurrency": "USD",
"requestedTargets": ["EUR", "GBP", "JPY", "BTC"],
"unsupportedTargets": ["BTC"]
},
"baseCurrency": "USD",
"asOfDate": "2026-09-11T00:00:00Z",
"rates": [
{ "currency": "EUR", "name": "Euro", "rate": 0.86266 },
{ "currency": "GBP", "name": "British Pound", "rate": 0.7403 },
{ "currency": "JPY", "name": "Japanese Yen", "rate": 154.04 }
],
"metadata": {
"generatedAtUtc": "2026-09-13T18:26:50Z",
"sources": ["Frankfurter API (frankfurter.dev) — ECB reference rates"]
},
"dataProvidedBy": "Frankfurter (frankfurter.dev), based on European Central Bank reference rates",
"termsOfServiceUrl": "https://frankfurter.dev/",
"dataPullDateTime": "2026-09-13T18:26:50.5931717Z",
"gimmeeVersion": "v1.0.0"
}
| Field | Type | Meaning |
|---|---|---|
query.baseCurrency |
string | The base currency after normalization (upper-cased, defaulted to USD if blank). |
query.requestedTargets |
string[] | The target codes you asked for, upper-cased and de-duplicated. Empty means "all available". |
query.unsupportedTargets |
string[] | Requested targets the ECB doesn't publish (e.g. BTC, XAU). These are missing from rates - check this list rather than assuming a missing entry is a bug. Empty when every target was found. |
baseCurrency |
string | The currency all rates are expressed against. |
asOfDate |
string (ISO 8601 UTC) | The ECB publication date the rates are effective for, as UTC midnight. On weekends/holidays this is the most recent business day - a Sunday call returns Friday's date. Not a real-time timestamp. |
rates[] |
object[] | One entry per target currency that was found, sorted by currency code. |
rates[].currency |
string | Target currency ISO 4217 code, e.g. "EUR". |
rates[].name |
string | Full currency name, e.g. "Euro". Empty string (never null) in the rare case the name lookup is unavailable. |
rates[].rate |
number | How many units of currency equal 1 unit of baseCurrency. Convert with amountInBase * rate. Precision is whatever the ECB publishes (typically 4-5 significant digits). |
metadata.generatedAtUtc |
string (ISO 8601 UTC) | When this response was assembled. |
metadata.sources |
string[] | Upstream source(s) used. |
dataProvidedBy |
string | Attribution for the upstream data source. |
termsOfServiceUrl |
string | Link to the upstream source's terms. |
dataPullDateTime |
string (ISO 8601 UTC) | When this DataGrab pulled the data. |
gimmeeVersion |
string | This DataGrab's own contract version tag. |
| Status | Meaning | When it happens |
|---|---|---|
| 401 | Unauthorized | Missing or invalid x-api-key |
| 404 | Not found | Empty {params} segment - send at least a base currency (USD). |
| 429 | Quota exceeded | Monthly 1,000-call quota used up - resets on your billing cycle date |
| 502 | Request failed | Both bad input and upstream failure come back as 502 - do not branch on the status code to tell them apart; read the message, which is written for a person and safe to show as-is. The body is plain text, not JSON - use response.text(), not .json(). Bad input: base isn't 3 letters, isn't one the ECB publishes (message lists every supported code), or the only target is the base itself. Upstream: the message says the rate source is temporarily unavailable - retry shortly. |
{base} with no targets to get every rate in one call, then convert locally, rather than one call per pair.rates and reported in query.unsupportedTargets; the call still succeeds with the rest.rate: rate is target-per-base. To go the other way (target → base) divide: amountInTarget / rate.response.ok before parsing. Error responses carry a plain-text message, not a JSON body, so an unconditional .json() throws on failure and hides the actual message.messageType: Finance.Currency.Quote
status: production
price: paid, $9/mo
quota: 1000/month
lastVerified: 2026-09-13