# Currency Exchange Rates API (`sfoln/fx-rates`) Actor

Get latest or historical exchange rates for any currency pairs, with amount conversion: ECB and 100+ central-bank reference rates via Frankfurter, data back to 1948. $0.50 per 1,000 rates; invalid pairs and dates without data are free.

- **URL**: https://apify.com/sfoln/fx-rates.md
- **Developed by:** [SFOLN LLC](https://apify.com/sfoln) (community)
- **Categories:** Developer tools, Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 exchange rates

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**Currency Exchange Rates API** gets **latest or historical exchange rates for any list of currency pairs** and converts an amount in the same call. Rates are mid-market reference rates published by the European Central Bank and 100+ other central banks and official sources, blended by the open-source [Frankfurter](https://frankfurter.dev/) service (data back to 1948). Ideal for invoicing, e-commerce price lists, accounting exports, spreadsheets and AI agents that need a reliable, citable rate.

- **$0.50 per 1,000 rates**, charged only per returned rate – malformed pairs, unknown currencies and dates without data are free.
- Pairs that share a base currency and date are fetched together, so large lists finish fast.
- Same JSON for the sync API, async runs and the Console; per-run spend cap honoured (`Maximum cost per run`).

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `pairs` | string\[] or object\[] | – | `BASE/QUOTE` ISO 4217 codes (`USD/EUR`, `usd eur`, `USDEUR`), optional `@YYYY-MM-DD` for a historical rate. Objects: `{ "base": "USD", "quotes": ["EUR","JPY"], "date": "2024-01-05", "amount": 250 }`. |
| `amount` | string | "1" | Amount in the base currency to convert (applies to pairs without their own `amount`): a plain number written as a string, with a decimal point (`"100"`, `"99.95"`); the API rejects a bare number here. Thousands separators, decimal commas, currency signs or negative values make the pair `skipped_invalid`. |
| `date` | string | latest | Historical date for pairs without their own `@date`. |
| `maxPairs` | integer | 1000 | Safety cap for this run; pairs beyond it are ignored and counted as `inputItemsDropped` in the `OUTPUT` record. |
| `concurrency` | integer | 5 | Parallel workers. |
| `includeRaw` | boolean | false | Attach the raw upstream row. |

```json
{
  "pairs": ["USD/EUR", "EUR/GBP", "GBP/JPY@2024-01-05"],
  "amount": "100"
}
```

### Output

One dataset record per pair:

```json
{
  "input": { "pair": "USD/EUR", "base": "USD", "quote": "EUR", "amount": 100 },
  "pair": "USD/EUR",
  "base": "USD",
  "quote": "EUR",
  "rate": 0.89273,
  "inverseRate": 1.120159511,
  "date": "2026-10-14",
  "requestedDate": null,
  "amount": 100,
  "converted": 89.273,
  "status": "ok",
  "charged": true,
  "chargedEvent": "fx-rate",
  "source": "frankfurter (ECB and other central banks)",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}
```

| Field | Description |
| --- | --- |
| `rate` | Units of `quote` per 1 `base` (mid-market reference rate). |
| `inverseRate` | 1 / `rate`, rounded to 10 significant digits. |
| `date` | Date of the reference rate. Latest rates are updated once per working day. |
| `requestedDate` | The date you asked for (`null` = latest). |
| `amount`, `converted` | Amount in base currency and `amount × rate` in quote currency (6 decimals; round for display). |

**`status`**: `ok` – rate returned, charged. `not_found` – the rate service has no rate for that pair or date, not charged. `skipped_invalid` – not a valid pair, an unsupported currency code, an impossible or future date (e.g. `2024-02-30`) or an invalid `amount`; never sent upstream, not charged. `error` – upstream unavailable or the request was blocked, not charged. `skipped_budget` / `skipped_free_plan` – not processed because of your cost cap or the free-plan limit. The key-value store record `OUTPUT` holds run totals.

### Pricing

| Event | Price | When charged |
| --- | --- | --- |
| Exchange rate (`fx-rate`) | **$0.0005** per rate ($0.50 / 1,000) | once per pair (and date) with `status: "ok"` |

Set **Maximum cost per run** to cap spend; when the cap is reached the remaining pairs are returned with `status: "skipped_budget"` and are not charged. Accounts on the Apify free plan can process up to 10 items per run; upgrade to any paid plan for full batches.

### Use with AI agents (MCP)

Use this Actor from Claude, ChatGPT, Cursor, VS Code or any other MCP client through the [Apify MCP server](https://mcp.apify.com). Add this server URL to your client and sign in with your Apify account when asked:

```text
https://mcp.apify.com?tools=sfoln/fx-rates
```

To run the MCP server locally instead, start `npx -y @apify/actors-mcp-server --tools sfoln/fx-rates` with your `APIFY_TOKEN` in the environment.

Example prompt:

> Get today's USD/EUR, EUR/GBP and GBP/JPY exchange rates and convert 2,500 USD to EUR.

Runs started by an agent are billed like any other run (see Pricing). Agents can cap what a run may spend with `maxTotalChargeUsd`.

### API usage

Run the Actor and get its dataset items in one call (the call waits up to 5 minutes for the run to finish):

```bash
curl -X POST "https://api.apify.com/v2/acts/sfoln~fx-rates/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"pairs": ["USD/EUR", "EUR/GBP", "GBP/JPY@2024-01-05"]}'
```

For large inputs, start the run asynchronously and download the dataset when it has finished:

```bash
## 1. Start a run: the response holds the run ID (data.id) and its dataset ID (data.defaultDatasetId)
curl -X POST "https://api.apify.com/v2/acts/sfoln~fx-rates/runs" \
  -H "Authorization: Bearer <APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"pairs": ["USD/EUR", "EUR/GBP", "GBP/JPY@2024-01-05"]}'
## 2. Repeat until data.status is SUCCEEDED (each call waits up to 60 s)
curl "https://api.apify.com/v2/actor-runs/<runId>?waitForFinish=60" -H "Authorization: Bearer <APIFY_TOKEN>"
## 3. Download the results (format=json, csv or xlsx)
curl "https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json" -H "Authorization: Bearer <APIFY_TOKEN>"
```

Python ([apify-client](https://pypi.org/project/apify-client/)):

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("sfoln/fx-rates").call(run_input={"pairs": ["USD/EUR", "EUR/GBP", "GBP/JPY@2024-01-05"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

Instead of polling, you can attach a webhook to the run (see Integrations). The API tab of this page shows the same calls for JavaScript and the Apify CLI.

#### More API examples

Synchronous:

```bash
curl -X POST "https://api.apify.com/v2/acts/sfoln~fx-rates/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"pairs": ["USD/EUR", "EUR/GBP@2024-01-05"], "amount": "100"}'
```

Asynchronous (large lists):

```bash
curl -X POST "https://api.apify.com/v2/acts/sfoln~fx-rates/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" -d '{"pairs": [{"base": "USD", "quotes": ["EUR", "GBP", "JPY", "CHF"]}]}'
## → poll /v2/actor-runs/<runId>, then GET /v2/datasets/<defaultDatasetId>/items
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("sfoln/fx-rates").call(run_input={"pairs": ["USD/EUR", "USD/JPY"], "amount": "250"})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["pair"], item["rate"], item["converted"], item["date"])
```

### Integrations

- **Make, Zapier and n8n:** run `sfoln/fx-rates` with the Apify app (in n8n, the Apify node) and pass the dataset items to the next step of your workflow.
- **Google Sheets:** add the items to a sheet with the Google Sheets step of Make, Zapier or n8n, or download them as CSV or Excel from the run's Storage tab or the API (`format=csv` or `format=xlsx`).
- **Webhooks:** get a POST request when a run succeeds or fails: add a webhook in the Actor's Integrations tab, or pass `webhooks` when you start a run through the API.
- **Schedules:** run it hourly, daily or weekly with the same input from Apify Schedules; every run keeps its results in its own dataset.
- **More:** Slack, Google Drive, GitHub, LangChain, LlamaIndex and other [Apify integrations](https://docs.apify.com/platform/integrations).

### Related Actors

- [Geocoding API – Address to Coordinates](https://apify.com/sfoln/geocode-address)
- [Historical Weather Data API](https://apify.com/sfoln/historical-weather)
- [VIN Decoder API – Specs, Recalls & Safety](https://apify.com/sfoln/vin-decoder)

See [all our Actors](https://apify.com/sfoln) on Apify Store.

### FAQ

#### How much does it cost, and am I charged for failed items?

You pay per event at the prices under Pricing above, plus a run start fee of $0.00005 per GB of memory, with no subscription; platform usage is included. Errors and skipped items (`skipped_…` statuses) are never charged; a lookup that finds nothing is charged only where Pricing says so, and every record's `charged` field shows whether it was billed. Set **Maximum cost per run** to cap what a single run can spend.

#### How fresh is the data?

Each run queries its source while it runs, so you get what the source returns at that moment. Source-specific details, such as how often a provider refreshes its own database, are under Limits & notes.

#### What are the limits?

Per-run caps (for example the maximum number of items) are listed under Input, source limits under Limits & notes, and the free-plan limit under Pricing. For big batches, start the run asynchronously (see API usage) and read the dataset when it has finished.

#### Can I schedule runs or get results by webhook?

Yes. Create a schedule in Apify Console to run it hourly, daily or weekly with the same input, and add a webhook to get a POST request when a run finishes (see Integrations).

#### What does this Actor record about my runs?

This Actor records operational metrics about each run (item counts, duration, charges, error codes and a pseudonymous hash of your Apify user ID) to monitor reliability and costs. It never stores your input or results.

#### How do I get help?

Open an issue in the Actor's Issues tab and include the link to the run, so we can reproduce the problem. Feature requests are welcome there too.

### Limits & notes

- Data source: Frankfurter (frankfurter.dev), which blends reference rates from the European Central Bank and other central banks and official sources. Blended rates are free to use commercially; for compliance use cases that require one official source, note that this Actor returns the blended rate.
- Rates are daily mid-market reference rates, not live trading quotes, bid/ask prices or card-network rates. Weekend and holiday dates return the rate published for that date by Frankfurter.
- Single dates only (no time series in one record). Currency codes are checked against Frankfurter's currency list (loaded at the start of each run, see frankfurter.dev); unsupported codes are returned as `skipped_invalid`.

# Actor input Schema

## `pairs` (type: `array`):

Pairs as BASE/QUOTE with ISO 4217 codes, e.g. USD/EUR. Add @YYYY-MM-DD for a historical rate (EUR/GBP@2024-01-05). API callers can also pass objects {"base":"USD","quotes":\["EUR","JPY"],"date":"2024-01-05","amount":250}. Accounts on the Apify free plan can process up to 10 currency pairs per run.

## `amount` (type: `string`):

Amount in the base currency to convert: a plain number with a decimal point, e.g. 100 or 99.95 (no thousands separators, decimal commas or currency signs; otherwise the pairs are skipped as invalid). Default 1.

## `date` (type: `string`):

Historical date (YYYY-MM-DD) applied to pairs without their own @date. Leave empty for the latest rates.

## `maxPairs` (type: `integer`):

Safety cap on the number of pairs processed in this run.

## `concurrency` (type: `integer`):

Parallel workers. Pairs sharing a base currency and date are fetched in one request.

## `includeRaw` (type: `boolean`):

Attach the unmodified Frankfurter row to each record.

## Actor input object example

```json
{
  "pairs": [
    "USD/EUR",
    "EUR/GBP",
    "GBP/JPY@2024-01-05"
  ],
  "amount": "1",
  "maxPairs": 1000,
  "concurrency": 5,
  "includeRaw": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "pairs": [
        "USD/EUR",
        "EUR/GBP",
        "GBP/JPY@2024-01-05"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sfoln/fx-rates").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "pairs": [
        "USD/EUR",
        "EUR/GBP",
        "GBP/JPY@2024-01-05",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("sfoln/fx-rates").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "pairs": [
    "USD/EUR",
    "EUR/GBP",
    "GBP/JPY@2024-01-05"
  ]
}' |
apify call sfoln/fx-rates --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sfoln/fx-rates"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/eZo6z4nO6ccpX4DGa/builds/MRhOWBwLQDrdFxxXt/openapi.json
