API Documentation
Everything you need to integrate PriceFeed Pro into your application.
Getting Started
1. Create an account and get your API key.
2. Include your API key in every request via the X-API-Key header.
3. Base URL: https://your-domain.com
Authentication
All API requests require an API key. Pass it as a header:
GET /api/v1/market/symbols HTTP/1.1
Host: api.example.com
X-API-Key: $PRICEFEED_API_KEYKeep your API key on the server side only. Never expose it in client-side JavaScript or public repositories.
API keys start with pf_ and are 67 characters long.
REST API
/api/v1/market/symbols?search=§or=&page=1&limit=50List available symbols, optionally filtered by search term and sector. Paginated.
// Response
{
"success": true,
"data": {
"symbols": [
{ "symbol": "XAUUSD", "display_name": "Gold", "sector": "metals", "digits": 2 },
{ "symbol": "EURUSD", "display_name": "EUR/USD", "sector": "forex", "digits": 5 }
],
"total": 150,
"page": 1,
"limit": 50
}
}/api/v1/market/history/{symbol}?tf=60&limit=500&from=&to=Get OHLC historical bars. Timeframes (in minutes): 1, 5, 15, 30, 60, 240, 1440, 10080, 43200. Requires Pro or Enterprise plan.
Bars are returned newest-first and capped by limit (default 500, max 5000). With only from set, the response contains the newest limit bars at or after from — page backward by setting the next to to the oldest time returned. from/to must be full RFC 3339 (e.g. 2026-02-10T00:00:00Z). There is no page= parameter on this endpoint.
// GET /api/v1/market/history/XAUUSD?tf=60&limit=5
{
"success": true,
"data": {
"symbol": "XAUUSD",
"source_id": "ORBEX-live-1",
"timeframe": 60,
"broker_tz": "Europe/Athens",
"bars": [
{
"source_id": "ORBEX-live-1",
"symbol": "XAUUSD",
"timeframe": 60,
"time": "2026-05-04T01:00:00Z",
"broker_time": "2026-05-04T04:00:00+03:00",
"open": 2650.5, "high": 2655.0, "low": 2648.0, "close": 2652.0,
"volume": 123
}
],
"count": 1
}
}/api/v1/market/tick/{symbol}Get the latest tick snapshot for a single symbol. Also available: /api/v1/market/ticks?symbols=EURUSD,GBPUSD for multiple symbols.
Each response includes broker_time (RFC 3339 with the broker's offset, e.g. 2026-05-04T04:00:00+03:00) and broker_tz (IANA zone, e.g. Europe/Athens). market_closed reflects the broker's schedule; data_stale goes true when no fresh tick has arrived for ~2 minutes and is decoupled from market_closed.
// GET /api/v1/market/tick/XAUUSD
{
"success": true,
"data": {
"symbol": "XAUUSD",
"source": "ORBEX-live-1",
"bid": "2654.21",
"ask": "2654.45",
"high": "2660.10",
"low": "2649.80",
"spread": 24,
"trade_mode": 4,
"time": "2026-05-04T01:00:00Z",
"broker_time": "2026-05-04T04:00:00+03:00",
"broker_tz": "Europe/Athens",
"market_closed": false,
"data_stale": false,
"trading_hours": "Sun:;Mon:00:02-23:59;..."
}
}/api/v1/account/profileGet your subscriber profile, subscription details, and usage stats. Requires JWT Bearer token (not API key).
WebSocket Streaming
Connect via native WebSocket to receive real-time price ticks and OHLC bars.
Connection URL: wss://your-host/ws/v1/stream?api_key=YOUR_API_KEY
Authentication is done via the api_key query parameter during the initial connection.
JavaScript (Node.js / Browser)
// Load API key from environment variable — never hardcode it
const ws = new WebSocket(
"wss://api.example.com/ws/v1/stream?api_key=" + process.env.PRICEFEED_API_KEY
);
ws.onopen = () => {
// Subscribe to tick data
ws.send(JSON.stringify({
action: "subscribe",
symbols: ["XAUUSD", "EURUSD"]
}));
// Subscribe to OHLC bars (optional)
ws.send(JSON.stringify({
action: "subscribe_bars",
symbols: ["XAUUSD"],
timeframes: [1, 5, 60]
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case "connected":
console.log("Plan:", msg.plan, "Sources:", msg.sources);
break;
case "tick":
// msg fields: symbol, source, bid, ask, high, low, spread, trade_mode,
// time (UTC), broker_time (RFC 3339 + offset), broker_tz, market_closed,
// data_stale (true when no fresh tick in ~2 min), trading_hours.
console.log(msg.symbol, msg.bid, msg.ask, "spread:", msg.spread,
msg.data_stale ? "(stale)" : "");
break;
case "error":
console.error(msg.code + ":", msg.message);
break;
}
};
// Unsubscribe
ws.send(JSON.stringify({
action: "unsubscribe",
symbols: ["EURUSD"]
}));Python
import os
import asyncio
import websockets
import json
async def connect():
# Load API key from environment variable — never hardcode it
api_key = os.environ["PRICEFEED_API_KEY"]
uri = f"wss://api.example.com/ws/v1/stream?api_key={api_key}"
async with websockets.connect(uri) as ws:
# Subscribe to tick data
await ws.send(json.dumps({
"action": "subscribe",
"symbols": ["XAUUSD", "EURUSD"]
}))
# Listen for messages
async for message in ws:
data = json.loads(message)
if data["type"] == "connected":
print(f"Connected - Plan: {data['plan']}")
elif data["type"] == "tick":
# Each tick also carries broker_time, broker_tz, market_closed,
# data_stale (True when no fresh tick in ~2 min), trading_hours.
stale = " (stale)" if data.get("data_stale") else ""
print(f"{data['symbol']}: {data['bid']}/{data['ask']} spread={data['spread']}{stale}")
elif data["type"] == "error":
print(f"Error [{data['code']}]: {data['message']}")
asyncio.run(connect())Rate Limits
| Tier | Requests/min | Max Symbols |
|---|---|---|
| Free | 10 | 5 |
| Basic | 60 | 20 |
| Pro | 300 | 100 |
| Enterprise | 9,999 | Unlimited |
Exceeding limits returns 429 Too Many Requests with a Retry-After header.
Error Codes
| Code | Status | Description |
|---|---|---|
| MISSING_API_KEY | 401 | No API key provided |
| INVALID_API_KEY | 401 | API key is invalid or inactive |
| API_KEY_REVOKED | 401 | API key has been revoked |
| ACCOUNT_INACTIVE | 403 | Subscriber account is inactive |
| TRIAL_EXPIRED | 403 | Free trial has expired, please upgrade |
| CONNECTION_LIMIT | 429 | Maximum WebSocket connections exceeded for your plan |
| SYMBOL_LIMIT | WS | Maximum symbol subscriptions exceeded for your plan |
| RATE_LIMIT_EXCEEDED | 429 | Too many requests for your plan |
| RATE_LIMITED | 429 | Too many failed auth attempts (15 min lockout) |