fxapis-com Market data API
Prices from each account's own broker, read live from its terminal. Each broker quotes differently, and these are the prices that account trades at.
Prices from each account's own broker, read live from its terminal. Each broker quotes differently, and these are the prices that account trades at.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/fxapis-com:fxapis-com-market-data-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
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: fxapis Market data API
version: 0.1.0
description: 'fxapis is the MetaTrader 5 API. Connect an MT5 account once, then trade it, read its positions
and its history over plain HTTP. Choose whether each account stays connected or comes online
only when you need it.
### Conventions
- Every successful response is `{ "data": … }`; every failure is `{ "error": { "code", "message" } }`.
Match on `code`, which is stable. `message` is written for a human and may change.
- Every response carries `requestId`. Quote it in a support request and the entire call can be found.
- Times are RFC 3339 in UTC. Money and prices are never floats in a request body.
### Bringing an account online is not instant
A broker login takes as long as the broker takes — usually seconds, occasionally much longer.
`POST /accounts/{id}/warm` brings an account online and returns **202** with a `pollUrl` rather than
holding the request open, so your client''s timeout never becomes a question about someone else''s
network. Poll `GET /accounts/{id}/status` until `state` is `ready`.
### Credentials
The MT5 password you send is encrypted before it is stored, with a data key that is bound to that
one account, and is never returned by any endpoint, written to the account record or included in
a log line. We cannot show it back to you — if it is lost, it is reset at the broker.'
servers:
- url: https://api.fxapis.com
description: Production
security:
- apiKey: []
tags:
- name: Market Data
description: Prices from each account's own broker, read live from its terminal. Each broker quotes differently, and these are the prices that account trades at.
paths:
/v1/accounts/{id}/quotes:
get:
summary: Live prices from the account's broker
tags:
- Market Data
description: 'Bid, ask and spread for up to 20 symbols or instruments, read from the account''s own MetaTrader terminal — the prices this account trades at. The account must be online (409 `ACCOUNT_NOT_READY` otherwise).
Every quote carries `time`, `brokerTime` and `ageMs`; judge freshness from them. `stale` is true only while the market is open and the last tick is over 60 seconds old; a closed market answers its last price with `marketOpen: false`. A symbol the broker does not have answers `status: unknown_symbol` in its place. Poll this; there is no stream. Calls that reach the terminal are charged to the account''s live budget (300 a minute + 50, across every caller; cached answers are free), and past it this answers 429 `RATE_LIMITED` with `retry-after`. An account whose terminal is still on an older worker — rare — answers 501 `CAPABILITY_UNAVAILABLE` instead.'
parameters:
- schema:
type: string
example: EURUSD,XAUUSD
in: query
name: symbols
required: false
description: 'Broker symbols, comma-separated, exactly as this broker names them: `EURUSD.a,XAUUSD.a`.'
- schema:
type: string
example: XAUUSD,US30
in: query
name: instruments
required: false
description: Instruments (`GET /v1/instruments`), comma-separated; each is quoted as this account's own symbol for it.
- schema:
type: string
format: uuid
in: path
name: id
required: true
responses:
'200':
description: Default Response
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
type: object
properties:
symbol:
type: string
example: EURUSD
instrument:
type:
- 'null'
- string
description: The instrument you asked by, when you asked by one.
status:
type: string
enum:
- ok
- no_price
- unknown_symbol
description: '`no_price`: the broker has sent no price for it yet. `unknown_symbol`: this broker has no such symbol.'
bid:
type:
- 'null'
- string
example: '1.08450000'
ask:
type:
- 'null'
- string
example: '1.08462000'
spread:
type:
- 'null'
- integer
description: Ask minus bid, in points.
example: 12
digits:
type:
- 'null'
- integer
description: Decimal places the broker quotes this symbol to.
example: 5
brokerTime:
type:
- 'null'
- string
description: The last tick's time on the broker's own clock, as its terminal shows it. Not UTC.
example: '2026-10-15 15:00:00.123'
time:
type:
- 'null'
- string
format: date-time
description: The last tick's time, in UTC. Always given when there is a tick, closed market included.
observedAt:
type: string
format: date-time
description: When the terminal was read.
ageMs:
type:
- 'null'
- integer
description: How old the tick was when it was read.
stale:
type: boolean
description: True only when the market is open (by the broker's sessions) and the last tick is more than 60 seconds old. A closed market's last price is not stale. Judge freshness for your own purposes from `time` and `ageMs`.
marketOpen:
type:
- 'null'
- boolean
description: From the broker's own trading sessions. Null until the terminal has reported them (a minute or so after it first comes online).
tradeMode:
type:
- 'null'
- string
enum:
- full
- longOnly
- shortOnly
- closeOnly
- disabled
- null
description: 'What the broker allows on this symbol right now, read with the price: `closeOnly` and `disabled` allow no new positions. Null for an unknown symbol.'
required:
- symbol
- status
- stale
'400':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'401':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'404':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'409':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'422':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'429':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'501':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'503':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
operationId: getV1AccountsByIdQuotes
x-operation-id-source: derived
/v1/accounts/{id}/candles:
get:
summary: Price history (candles) from the account's broker
tags:
- Market Data
description: 'Open, high, low and close bars for one symbol or instrument, read from the account''s own MetaTrader terminal: `timeframe` M1, M5, M15, M30, H1, H4, D1, W1 or MN1, and up to 1,000 bars (`count`, default 100) counting back from the current one, oldest first; the last bar is still forming. Times are when each bar opened, in UTC (converted with the broker''s current clock offset, so bars from before its last daylight-saving change can be an hour out). `tickVolume` counts price changes, not traded volume. The account must be online (409 `ACCOUNT_NOT_READY` otherwise). Each call reaches the terminal and is charged to the account''s live budget (300 a minute + 50, shared with quotes and fresh figures); past it this answers 429 `RATE_LIMITED` with `retry-after`.
An account whose terminal is still on an older worker — rare — answers 501 `CAPABILITY_UNAVAILABLE` instead.'
parameters:
- schema:
type: string
example: XAUUSD
in: query
name: symbol
required: false
description: The broker symbol, exactly as this broker names it. Send this or `instrument`.
- schema:
type: string
example: XAUUSD
in: query
name: instrument
required: false
description: An instrument (`GET /v1/instruments`), read as this account's own symbol for it. Send this or `symbol`.
- schema:
type: string
enum:
- M1
- M5
- M15
- M30
- H1
- H4
- D1
- W1
- MN1
in: query
name: timeframe
required: true
description: 'The bar size: minutes (M), hours (H), a day, a week or a month.'
- schema:
type: integer
minimum: 1
maximum: 1000
default: 100
in: query
name: count
required: false
description: How many bars, counting back from the current one. At most 1,000.
- schema:
type: string
format: uuid
in: path
name: id
required: true
responses:
'200':
description: Default Response
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
symbol:
type: string
example: XAUUSD
instrument:
type:
- 'null'
- string
description: The instrument you asked by, when you asked by one.
timeframe:
type: string
example: H1
digits:
type: integer
description: Decimal places the broker quotes this symbol to; prices are written to them.
example: 2
candles:
type: array
description: Oldest first. The last bar is the current one, still forming.
items:
type: object
properties:
time:
type: string
format: date-time
description: When the bar opened, in UTC.
example: '2026-10-23T13:00:00Z'
open:
type: string
example: '2650.10'
high:
type: string
example: '2655.25'
low:
type: string
example: '2648.00'
close:
type: string
example: '2652.50'
tickVolume:
type: integer
description: Price changes in the bar (MetaTrader's tick volume), not traded volume.
example: 1234
spread:
type: integer
description: The bar's spread in points, as the broker recorded it.
example: 35
required:
- time
- open
- high
- low
- close
- tickVolume
- spread
required:
- symbol
- timeframe
- digits
- candles
'400':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'401':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'404':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'409':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'422':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'429':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'501':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
'503':
description: Default Response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Stable, machine-readable. Match on this, not on the message.
message:
type: string
description: For a human. May change between releases.
details:
type: array
items:
type: object
additionalProperties: true
required:
- code
- message
requestId:
type: string
description: Also on every response. Quote it in a support request and the whole call can be found.
operationId: getV1AccountsByIdCandles
x-operation-id-source: derived
components:
securitySchemes:
apiKey:
type: http
scheme: bearer
description: '`Authorization: Bearer fx_live_<id>_<secret>`.
A key is shown once, at creation. We cannot show it again or recover it for you.
Keys carry a label (`live` or `test`) in the key itself, so each configuration is easy to tell
apart. Both reach real brokers: test with a broker demo account.
Scopes are per key. A key without `accounts:write` can read accounts and nothing else.'
adminKey:
type: http
scheme: bearer
description: '`Authorization: Bearer fx_admin_<id>_<secret>`.
An admin key manages this workspace''s ordinary API keys (`/v1/api-keys`) and can do nothing else.
Only the workspace owner makes one, in the console, optionally limited to IP addresses and given
an expiry. Every request made with one is audited.'