Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/exchangerate-dev:exchangerate-dev-convert-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: exchangerate.dev Convert API
description: 'Live indicative foreign-exchange rates for developers. Explicit `source` and `market_session` labels on every response — live intraday (~60s) on trading days for all currencies, with ECB daily fallback in the 144-currency catalog (10296 unique pairs). Free tier: 5,000 calls/month, no card. Live rates 15 minutes delayed. MCP server: https://api.exchangerate.dev/v1/mcp/ · Docs: https://exchangerate.dev/docs'
contact:
url: https://exchangerate.dev/docs
version: '1.0'
tags:
- name: Convert
paths:
/v1/convert/{from_ccy}/{to_ccy}/{amount}:
get:
summary: Convert
operationId: convert_v1_convert__from_ccy___to_ccy___amount__get
parameters:
- name: from_ccy
in: path
required: true
schema:
type: string
title: From Ccy
- name: to_ccy
in: path
required: true
schema:
type: string
title: To Ccy
- name: amount
in: path
required: true
schema:
anyOf:
- type: number
- type: string
pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
title: Amount
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ConvertResponse'
'400':
description: Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: 'Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 'plan_gated: the caller''s plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not found, e.g. unknown_index or no_data_for_date.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'422':
description: Request validation failed.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: 'Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.'
headers:
X-RateLimit-Limit:
description: Limit for the window named by X-RateLimit-Scope.
schema:
type: integer
X-RateLimit-Remaining:
description: Requests left in that window (0 on a 429).
schema:
type: integer
X-RateLimit-Reset:
description: Unix time (seconds) when the window resets.
schema:
type: integer
X-RateLimit-Scope:
description: 'Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.'
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: The operation failed internally.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'503':
description: A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
tags:
- Convert
/v1/convert/{from_ccy}/{to_ccy}:
get:
summary: Convert
operationId: convert_v1_convert__from_ccy___to_ccy__get
parameters:
- name: from_ccy
in: path
required: true
schema:
type: string
title: From Ccy
- name: to_ccy
in: path
required: true
schema:
type: string
title: To Ccy
- name: amount
in: query
required: false
schema:
anyOf:
- type: number
- type: string
pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
default: '1'
title: Amount
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ConvertResponse'
'400':
description: Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: 'Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 'plan_gated: the caller''s plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not found, e.g. unknown_index or no_data_for_date.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'422':
description: Request validation failed.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: 'Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.'
headers:
X-RateLimit-Limit:
description: Limit for the window named by X-RateLimit-Scope.
schema:
type: integer
X-RateLimit-Remaining:
description: Requests left in that window (0 on a 429).
schema:
type: integer
X-RateLimit-Reset:
description: Unix time (seconds) when the window resets.
schema:
type: integer
X-RateLimit-Scope:
description: 'Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.'
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: The operation failed internally.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'503':
description: A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
tags:
- Convert
/v1/convert:
post:
summary: Convert Batch
operationId: convert_batch_v1_convert_post
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ConvertBatchRequest'
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ConvertBatchResponse'
'400':
description: Bad request. Codes include invalid_pair, unsupported_base, bad_date, invalid_amount, invalid_request, missing_parameter, unsupported_interval, unsupported_pair_interval and unsupported_index_interval.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: 'Authentication failed: invalid_api_key (or invalid_session_token on dashboard routes).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: 'plan_gated: the caller''s plan does not include this interval or history depth; forbidden: the request did not pass through the public origin.'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not found, e.g. unknown_index or no_data_for_date.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'422':
description: Request validation failed.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: 'Rate limit or quota exceeded: rate_limited (per-minute limit, X-RateLimit-Scope tier-rate-minute), ip_rate_limited (keyless per-IP hourly cap, anon-ip-hour) or quota_exceeded (monthly quota, tier-quota-month). Wait Retry-After seconds; do not retry a monthly quota error automatically. quota_unavailable means the quota store could not be read; retry after Retry-After.'
headers:
X-RateLimit-Limit:
description: Limit for the window named by X-RateLimit-Scope.
schema:
type: integer
X-RateLimit-Remaining:
description: Requests left in that window (0 on a 429).
schema:
type: integer
X-RateLimit-Reset:
description: Unix time (seconds) when the window resets.
schema:
type: integer
X-RateLimit-Scope:
description: 'Which limit applied: anon-ip-hour, tier-rate-minute or tier-quota-month.'
schema:
type: string
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: The operation failed internally.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'503':
description: A required data source or feature is temporarily unavailable, e.g. data_unavailable, live_unavailable, source_unavailable or service_unavailable.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
tags:
- Convert
components:
schemas:
MarketSession:
type: string
enum:
- open
- weekend
- interbank_closed
title: MarketSession
description: 'Computed from a clock, no feed (D9). `interbank_closed` = a known non-weekend closure
(e.g. an ECB/TARGET2 holiday detected via an empty Tier-C response — INGESTION §4).'
ConvertBatchResponse:
properties:
result:
type: string
title: Result
default: success
from:
type: string
title: From
conversions:
items:
$ref: '#/components/schemas/ConvertItem'
type: array
title: Conversions
source:
$ref: '#/components/schemas/Source'
sources:
additionalProperties:
$ref: '#/components/schemas/Source'
type: object
title: Sources
stale:
additionalProperties:
type: boolean
type: object
title: Stale
market_session:
$ref: '#/components/schemas/MarketSession'
timestamp:
type: string
title: Timestamp
data_updated_at:
type: string
title: Data Updated At
effective_at:
additionalProperties:
type: string
type: object
title: Effective At
notice:
type: string
title: Notice
type: object
required:
- from
- conversions
- source
- sources
- stale
- market_session
- timestamp
- data_updated_at
- effective_at
- notice
title: ConvertBatchResponse
Source:
type: string
enum:
- live
- ecb_daily
- market_daily
title: Source
description: 'Public `source` enum — wire contract (D2). NO `cached` value (cache lives in X-Cache).
`ecb_daily` is the only reference source (October 2026).
`market_daily` labels the stored daily close of the live market feed, for the currencies with
no reference fix, in date history and 1d time series; it is never a live rate.'
ErrorResponse:
properties:
result:
type: string
title: Result
default: error
code:
type: string
title: Code
message:
type: string
title: Message
type: object
required:
- code
- message
title: ErrorResponse
ConvertItem:
properties:
to:
type: string
title: To
amount:
type: number
title: Amount
rate:
type: number
title: Rate
converted:
type: number
title: Converted
derived:
type: boolean
title: Derived
derivation_bps_max:
anyOf:
- type: number
- type: 'null'
title: Derivation Bps Max
type: object
required:
- to
- amount
- rate
- converted
- derived
title: ConvertItem
ConvertBatchRequest:
properties:
from:
type: string
title: From
pairs:
items:
prefixItems:
- type: string
- anyOf:
- type: number
- type: string
pattern: ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$
type: array
maxItems: 2
minItems: 2
type: array
title: Pairs
additionalProperties: false
type: object
required:
- from
- pairs
title: ConvertBatchRequest
ConvertResponse:
properties:
result:
type: string
title: Result
default: success
from:
type: string
title: From
to:
type: string
title: To
amount:
type: number
title: Amount
rate:
type: number
title: Rate
converted:
type: number
title: Converted
derived:
type: boolean
title: Derived
derivation_bps_max:
anyOf:
- type: number
- type: 'null'
title: Derivation Bps Max
source:
$ref: '#/components/schemas/Source'
sources:
additionalProperties:
$ref: '#/components/schemas/Source'
type: object
title: Sources
stale:
type: boolean
title: Stale
market_session:
$ref: '#/components/schemas/MarketSession'
timestamp:
type: string
title: Timestamp
data_updated_at:
type: string
title: Data Updated At
notice:
type: string
title: Notice
type: object
required:
- from
- to
- amount
- rate
- converted
- derived
- source
- sources
- stale
- market_session
- timestamp
- data_updated_at
- notice
title: ConvertResponse