Developer documentation
CQS Public Signals API
This guide explains how to pull live trading signals from Crypto Quality Signals into your own bot, spreadsheet, or custom integration. If you already use Cornix, 3Commas, or similar, you can skip most of this — those platforms connect with your subscription ID through their own settings.
Production base URL:
https://api.cryptoqualitysignals.com
Quick start
The public API does one main thing: return open trading signals published by CQS within a time window you choose. You send your API key, read the JSON, and process the signals array.
- Choose your key: FREE for public signals, or your premium subscription ID from the CQS dashboard.
- Call GET or POST on https://api.cryptoqualitysignals.com/getSignal/ with that key.
- Parse the signals array. Each item includes entry zone, targets, stop loss, exchange, and direction.
Minimal request (free tier, last 5 minutes):
curl -s "https://api.cryptoqualitysignals.com/getSignal/?api_key=FREE&interval=5"
Authentication
Every request needs api_key. There is no separate Bearer token — pass the key as a query parameter (GET) or form field (POST).
Free access
Use the literal string FREE. You receive signals from the free and freemium channels. Volume and types are more limited than premium.
Premium access
After subscribing, your account gets a unique subscription ID — a long alphanumeric string. That value is your API key. Copy it exactly from the premium dashboard.
Premium keys unlock VIP signals. Wrong, expired, or inactive keys return error code 5.
The getSignal endpoint
| URL | https://api.cryptoqualitysignals.com/getSignal/ |
| Methods | GET, POST |
| Response | application/json, UTF-8 |
GET and POST behave the same. GET is handy for quick tests; POST works if you prefer form bodies.
Alternate path (same handler): https://api.cryptoqualitysignals.com/api/v1/getSignal
Request parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
api_key |
Yes | — | FREE or your premium subscription ID. |
interval |
No | 5 |
Look-back window in minutes (1–20). Only signals opened inside this window are returned. |
exchange |
No | — | Filter by exchange, e.g. binance, BINANCE_FUTURES, kucoin. |
currency |
No | — | Quote currency filter, e.g. USDT, BTC. |
type |
No | — | Signal horizon filter. Must match one of the valid types below. Empty = all types allowed for your tier. |
POST uses the same field names: api_key, interval, exchange, currency, type.
Response format
Every response uses the same envelope:
{
"error": 0,
"message": "Success",
"count": 2,
"signals": [ ... ]
}
error— Numeric status (0 = OK). See error codes.message— Human-readable status for logs.count— Length of the signals array.signals— List of signal objects; empty when nothing matched.
Example (one signal, fields may vary):
{
"error": 0,
"message": "Success",
"count": 1,
"signals": [
{
"id": "1847291",
"timestamp": "2026-05-24 14:32:05",
"exchange": "binance",
"currency": "USDT",
"coin": "BTC",
"direction": "LONG",
"buy_start": "94250.5",
"buy_end": "94400",
"target1": "95500",
"target2": "96200",
"target3": "97000",
"stop_loss": "93100",
"type": "SHORT TERM",
"ask": "94325",
"risk_level": "3"
}
]
}
When nothing is available: error 0, message "No new signals available", count 0, signals [].
Signal fields explained
Prices are returned as strings to avoid floating-point surprises. Parse them as decimals in your language.
id
Unique signal ID. Track it locally so you do not process the same open signal twice on the next poll.
timestamp
Publish time on our servers (YYYY-MM-DD HH:MM:SS).
exchange, currency, coin
Where to trade. Pair = coin/currency (example: BTC/USDT).
direction
LONG = buy expecting a rise. SHORT = sell or short (common on futures).
buy_start, buy_end
Suggested entry zone. Many traders scale in between these prices instead of market-buying at ask.
ask
Reference price at publish time. Bots often map this to their signal price field.
target1, target2, target3
Take-profit levels. Not every signal uses three — unused targets may be empty. Partial exits at each level are common.
stop_loss
Invalidation price. For LONG, exit if price reaches or crosses below this level.
type
Horizon bucket (see signal types).
risk_level
Internal risk score, usually 1–5. Higher = more aggressive setup.
leverage (futures only)
Suggested leverage on futures exchanges. Omitted on spot pairs.
Signal types
Pass one of these exact strings in the type parameter (spaces and slashes included):
SHORT TERMSHORT/MID TERMSCALPINGMID TERMLONG TERM
Unknown type → error 1 with a descriptive message.
Scalping (free tier)
Free scalping signals use a separate table. Request them with api_key=FREE and type=SCALPING.
- Only target1 is set (single take-profit).
- buy_start / buy_end are ±0.1% around ask.
- risk_level is always 3.
- BitMEX scalps are excluded from the free feed.
curl -s "https://api.cryptoqualitysignals.com/getSignal/?api_key=FREE&type=SCALPING&interval=10"
Futures exchanges & leverage
Futures signals use the exchange codes listed below. Use the exact value from the exchange field when filtering with the exchange parameter.
Supported futures exchange codes
Most rows use lowercase (e.g. binance_futures). The filter must match the stored value exactly.
-
binance_futuresBinance Futures -
bitget_futuresBitget Futures -
bitmexBitMEX -
bybitBybit -
deribitDeribit -
htx_futuresHTX Futures -
kucoin_futuresKucoin Futures -
okx_futuresOKX Futures
Leverage field
When you filter by any futures exchange code listed above, the response includes leverage — typically the midpoint of our min/max range. Without an exchange filter, leverage is omitted even for futures signals.
Confirm contract type and max leverage on your exchange before auto-trading.
Error codes
| Code | Typical message | What to do |
|---|---|---|
0 |
Success / No new signals | Normal. Check count. |
1 |
Missing key / Invalid type / Bad parameter | Fix the request. |
4 |
Unable to validate API Key | Billing DB unreachable — retry later. |
5 |
Invalid API Key / System unavailable | Wrong key, inactive subscription, or signals DB down. |
6 |
Rate limit exceeded | Slow down polling (limit may return in the future). |
How often to poll
There is no webhook for public delivery — you pull on a schedule.
- Every 30–60 seconds for scalping; 2–5 minutes is usually enough for swing signals.
- Set interval slightly wider than your poll period so you do not miss signals between requests.
- Deduplicate by id. The API returns all matching open signals in the window, not only brand-new ones.
- On error 4 or 5 with "unavailable", back off before retrying.
Trading bots & platforms
CQS premium works natively with 3Commas, Cornix, Zignaly, AnnyDeCrypto, Le-Trader, Nefertiti, 3C.exchange, and others. Those tools ask for your subscription ID in their UI — no JSON parsing required unless you want a custom setup.
Building your own bot? Map coin + currency to the exchange symbol, respect direction, enter between buy_start and buy_end, set stop at stop_loss, and scale out at target1–target3. Paper-trade first.
Code examples
GET — premium, Binance USDT, short term
curl -G "https://api.cryptoqualitysignals.com/getSignal/" \
--data-urlencode "api_key=YOUR_SUBSCRIPTION_ID" \
--data-urlencode "interval=15" \
--data-urlencode "exchange=binance" \
--data-urlencode "currency=USDT" \
--data-urlencode "type=SHORT TERM"
POST — form body
curl -s -X POST "https://api.cryptoqualitysignals.com/getSignal/" \
-d "api_key=FREE" \
-d "interval=5" \
-d "type=SCALPING"
Python
import requests
API_KEY = "YOUR_SUBSCRIPTION_ID" # or "FREE"
url = "https://api.cryptoqualitysignals.com/getSignal/"
params = {"api_key": API_KEY, "interval": 10, "exchange": "binance", "currency": "USDT"}
resp = requests.get(url, params=params, timeout=30)
data = resp.json()
if data["error"] != 0:
raise RuntimeError(f"API error {data['error']}: {data['message']}")
seen = set()
for sig in data["signals"]:
if sig["id"] in seen:
continue
seen.add(sig["id"])
print(sig["coin"], sig["direction"], sig["ask"])
JavaScript (Node 18+)
const params = new URLSearchParams({ api_key: "FREE", interval: "5" });
const res = await fetch(`https://api.cryptoqualitysignals.com/getSignal/?${params}`);
const data = await res.json();
if (data.error !== 0) throw new Error(`${data.error}: ${data.message}`);
for (const s of data.signals) console.log(s.id, s.coin);
PHP
$q = http_build_query(['api_key' => 'FREE', 'interval' => 5]);
$json = file_get_contents('https://api.cryptoqualitysignals.com/getSignal/?' . $q);
$data = json_decode($json, true);
if ($data['error'] !== 0) throw new Exception($data['message']);
foreach ($data['signals'] as $s) echo $s['id'], ' ', $s['coin'], PHP_EOL;
FAQ
- Where do I find my subscription ID?
- Log in to the CQS premium dashboard after purchase. Copy the subscription ID exactly into api_key.
- Why do I see the same signal twice?
- Open signals stay in the feed until we close them. Track id values you already handled.
- Are closed or hit-target signals returned?
- No. Only open signals within the time window are included.
- Is HTTPS required?
- Yes. Always use https://. Never send a premium key over plain HTTP.
- Need help?
- Premium members: use the support channel included in your plan. For outages, test a FREE request before opening a ticket.
Last updated: May 2026 · Applies to https://api.cryptoqualitysignals.com/getSignal/