Webhook API Reference

Complete reference for the TradeStaq webhook API used to trigger Signal Bot trades.

Overview

The Webhook API allows external services (like TradingView) to send trading signals to your Signal Bots. The webhook accepts a signal and queues it; the trade then runs straight away in the background, and its result appears in the bot's Signal Logs tab.

┌──────────────┐     POST      ┌──────────────┐     Execute     ┌──────────────┐
│  TradingView │──────────────▶│  TradeStaq   │────────────────▶│   Exchange   │
│   or Script  │   /webhooks   │   Server     │    Trade        │    (API)     │
└──────────────┘               └──────────────┘                 └──────────────┘

Endpoint

POST https://www.tradestaq.com/api/webhooks/trade/{webhookId}
ComponentDescription
Base URLhttps://www.tradestaq.com
Path/api/webhooks/trade/{webhookId}
MethodPOST
Content-Typeapplication/json

Finding Your Webhook ID

  1. Go to Dashboard → Signal Bots
  2. Click your bot
  3. Open the Webhook Setup tab
  4. Copy the webhook URL
  5. The ID is the last segment of the URL

Note: Anyone with this URL can send signals to your bot. Keep it private.

Request Format

The body is one JSON object. Every signal needs ticker and position; every other field is optional and falls back to the bot's settings.

Basic Signal

{
  "ticker": "BTCUSDT",
  "position": "long"
}

Full Signal

{
  "ticker": "BTCUSDT",
  "position": "long",
  "size": "0.01",
  "leverage": "5",
  "sl": "95000",
  "tp": "105000",
  "currentPrice": "97500",
  "comment": "RSI oversold entry"
}

Close Signal

{
  "ticker": "BTCUSDT",
  "position": "flat"
}

Limit Entry

{
  "ticker": "BTCUSDT",
  "position": "long",
  "price": "96000"
}

Request Fields

FieldRequiredDescription
tickerYesThe trading pair (pair also works)
positionYesWhat to do: open, close, or update a position (see below). action works when position is absent
priceNoLimit price for a long / short entry, or the price of a close_limit
sizeNoAmount in the base coin, e.g. 0.01 BTC
leverageNoLeverage for this entry, up to the bot's setting
slNoStop loss price
tpNoTake profit price
currentPriceNoCurrent price, a hint for sizing (marketPrice also works)
commentNoNote shown in Telegram trade notifications
exchangeNoRun the signal on matching exchange connections only
timeframeNoChart timeframe, checked against your plan
closePercentNoClose only this % of the position

ticker (required)

The trading pair. pair is accepted in its place; when both are sent, pair is used.

FormatExample
Without slashBTCUSDT
With slashBTC/USDT
With dashBTC-USDT
TradingView perpetualBTCUSDT.P (the part after the dot is dropped)

The pair is matched to your exchange's market, so BTC/USDT becomes BTC/USDT:USDT for futures on most exchanges.

Note: A bot with a fixed trading pair always trades its own pair; the signal still needs a ticker, but its value does not change the pair. On a Dynamic Pair bot, the ticker picks the pair.

position (required)

What the signal does. Values are not case-sensitive.

action is accepted in place of position: when a signal has no position (or an empty one), its action is used, with the same values and aliases. When both are sent, position wins.

ValueAliasesWhat happens
longbuyFutures: opens a long. If the bot holds a short, it closes the short first. Spot: buys.
shortsellFutures: opens a short. If the bot holds a long, it closes the long first. Spot: sells the coins the bot holds (spot never opens a short).
flatclose, exit, flattenCloses the bot's open position without opening a new one
close_longexit_longCloses the long only
close_shortexit_shortCloses the short only
update_slMoves the stop loss of the open position to sl (required)
update_tpMoves the take profit of the open position to tp (required)
close_limitCloses the open position with a limit order at price (required)
close_trailPuts a trailing stop on the open position
close_on_candleCloses the open position when the current candle of the bot's timeframe closes

Any other value (for example hold, breakeven or a typo) is refused: nothing is sent to the exchange, and Signal Logs shows Unsupported signal position. So is update_sl without a valid sl price, and update_tp without a valid tp price.

On futures, a long while the bot already holds a long (or a short while it holds a short) is ignored, unless DCA is on (see DCA below).

Note: On futures, sell is an entry: while the bot is long, it closes the long and opens a short. TradingView's {{strategy.order.action}} sends sell for a strategy's exit orders too, so use {{strategy.market_position}} (it sends flat for an exit) unless you want every exit to reverse.

price (optional)

With long or short, a price makes the entry a limit order at that price instead of a market order. A limit order may fill late, partly, or not at all.

  • With buy or sell, the entry goes out at market: the price is not used as a limit.
  • On spot, a short or sell with a price still sells the holding at market.
  • close_limit needs a price: it is the price of its closing limit order.

size (optional)

The amount to trade, in the coin you are buying or selling (the base currency): "0.01" on BTCUSDT trades 0.01 BTC. On exchanges that trade in contracts, TradeStaq converts it to contracts. The bot's Max Position Size, when set, caps it.

FormatExampleDescription
String number"0.01"0.01 coins
Number0.50.5 coins

Percentages are not supported: size is never a share of your balance, and a signal whose size is not a plain number (for example "25%") is refused. To trade a share of your balance, leave size out and set the bot's position sizing to a percentage.

contracts and amount are accepted in place of size (TradingView's {{strategy.order.contracts}}).

On a close (flat, close, close_long, close_short), a size closes that many coins of the position instead of all of it.

Default: the bot's position sizing.

leverage (optional)

The leverage for this entry, up to the bot's own leverage setting (default 1x).

FormatExampleDescription
String number"5"5x leverage
Number1010x leverage
  • A value above the bot's setting trades at the setting: an alert can lower the leverage, never raise it. To trade at a higher leverage, change the bot's leverage setting.
  • No entry goes above the exchange's maximum for that coin: when that is lower, the entry goes out at the exchange's maximum.
  • An entry that adds to a position the bot already holds goes out at that position's leverage, so the open position is not re-margined.

Default: the bot's leverage setting.

Note: Only applies to futures exchanges. Ignored for spot trading.

sl (optional)

Stop loss price for the position this signal opens, as an absolute price ("95000"). With update_sl, the new stop loss price.

TradeStaq watches the price and closes the position at market when it reaches the stop; the stop is not placed as an order on the exchange.

Note: Percentages are not supported: "2%" is read as a price of 2.

tp (optional)

Take profit price for the position this signal opens, as an absolute price ("105000"). With update_tp, the new take profit price.

Like the stop loss, TradeStaq watches it and closes the position at market when the price reaches it.

currentPrice (optional)

The current price of the coin, for example TradingView's {{close}}. TradeStaq uses it to size the order instead of fetching the price first. marketPrice is accepted in its place; when both are sent, currentPrice is used.

It is only a hint: it never makes a limit order (that is price).

comment (optional)

A note shown in the bot's Telegram trade notifications, for example "RSI oversold entry".

exchange (optional)

For a bot on several exchange connections: run this signal only on the connections whose exchange name or account label contains this text (not case-sensitive), for example "binance" or "Main Account". When nothing matches, the signal fails with No active authorized exchanges.

Default: every exchange connection on the bot.

timeframe (optional)

The chart timeframe the signal came from (interval and tf also work). When your plan limits timeframes, an entry from a timeframe it does not allow is refused.

closePercent (optional)

With flat, close, close_long or close_short: close this percentage of the position (above 0 and below 100) instead of all of it. A part below the exchange's minimum order is skipped, and the whole position closes when what would remain is below the minimum.

Trailing stop fields (close_trail)

FieldDescription
trailPercentTrail distance in %. Default: the bot's trailing stop setting, else 1%
activationPercentStart trailing once the position is this % in profit
activationPriceStart trailing once the price reaches this level (used instead of activationPercent)

DCA

There are no DCA fields in the signal. With DCA enabled in the bot's settings, each entry signal is the next DCA level: the first opens the position (level 1), and each further entry on the same side adds a level instead of being ignored. A level's size is the signal's size (or the bot's position sizing) times that level's size percentage. TradeStaq does not place level orders by itself: your signal source decides when each level goes in.

DCA Example Flow

// Level 1 - Initial entry
{"ticker": "BTCUSDT", "position": "long"}

// Level 2 - Price dropped 3%, add more
{"ticker": "BTCUSDT", "position": "long"}

// Level 3 - Price dropped 6%, add more
{"ticker": "BTCUSDT", "position": "long"}

// Close - Exit full position
{"ticker": "BTCUSDT", "position": "flat"}

Once the bot's max levels are in, a further entry fails with Max DCA levels reached. See DCA.

Response Codes

The reply only says whether the signal was accepted. Whether a trade was placed shows in Signal Logs.

Accepted (202)

The signal was received and queued for the bot.

{
  "message": "Trade Queued",
  "bot": "BTC RSI Strategy"
}

A 202 does not mean a trade was placed: the signal can still be ignored or refused when it runs (see Signal Results below). A signal sent to a paused or stopped bot is accepted too, and then refused with Bot is not active.

Client Errors (4xx)

CodeReply messageCommon Causes
400Invalid JSON format. Ensure you are sending a valid JSON string.The body is not valid JSON
401Invalid signatureOnly for a bot with a signing secret: the signature header is missing or wrong (see below)
404Invalid Webhook IDNo Signal Bot has this webhook ID (a typo, or the bot was deleted)

Example Error Response:

{
  "message": "Invalid Webhook ID"
}

Server Errors (5xx)

CodeMeaningAction
500Internal ErrorRetry after delay
502Bad GatewayRetry after delay
503Service UnavailableRetry after delay

Signed Requests

A bot with a signing secret checks every request for an X-Signature (or X-Webhook-Signature) header: the HMAC-SHA256 of the raw request body with the secret, in hex. A request without a valid signature gets 401. A bot without a signing secret skips this check, and its webhook URL is the only key, so keep it private.

TradingView Integration

Alert Message Format

In TradingView, set your alert message to JSON:

{
  "ticker": "{{ticker}}",
  "position": "{{strategy.market_position}}",
  "currentPrice": "{{close}}"
}

Using TradingView Variables

VariableDescriptionExample
{{strategy.market_position}}Strategy position after the orderlong, short, flat
{{strategy.order.action}}Order directionbuy, sell
{{strategy.order.contracts}}Order size0.1
{{ticker}}SymbolBTCUSDT
{{close}}Current close price50000
{{open}}Current open price49800
{{high}}Current high price50100
{{low}}Current low price49700
{{volume}}Current volume1234.56
{{interval}}Chart timeframe60
{{time}}Candle timestamp2024-01-01T00:00:00Z
{{timenow}}Current timestamp2024-01-01T00:00:00Z

Pine Script Example

//@version=5
strategy("My Strategy", overlay=true)

// Your strategy logic
longCondition = ta.crossover(ta.sma(close, 10), ta.sma(close, 20))
shortCondition = ta.crossunder(ta.sma(close, 10), ta.sma(close, 20))

if longCondition
    strategy.entry("Long", strategy.long,
        alert_message='{"ticker":"{{ticker}}","position":"long","currentPrice":"{{close}}"}')

if shortCondition
    strategy.close("Long",
        alert_message='{"ticker":"{{ticker}}","position":"flat"}')

Setting Up the Alert

  1. Create alert on your strategy/indicator
  2. Set Webhook URL to your TradeStaq webhook URL
  3. Set Message to your JSON payload
  4. Enable the alert

Code Examples

cURL

curl -X POST https://www.tradestaq.com/api/webhooks/trade/your-webhook-id \
  -H "Content-Type: application/json" \
  -d '{"ticker":"BTCUSDT","position":"long"}'

Python

import requests

webhook_url = "https://www.tradestaq.com/api/webhooks/trade/your-webhook-id"

signal = {
    "ticker": "BTCUSDT",
    "position": "long",
    "size": "0.01",
    "sl": "95000",
    "tp": "105000"
}

response = requests.post(webhook_url, json=signal)
print(response.status_code, response.json())

JavaScript/Node.js

const axios = require('axios');

const webhookUrl = 'https://www.tradestaq.com/api/webhooks/trade/your-webhook-id';

const signal = {
  ticker: 'BTCUSDT',
  position: 'long',
  size: '0.01',
  sl: '95000',
  tp: '105000'
};

axios.post(webhookUrl, signal)
  .then(response => console.log(response.status, response.data))
  .catch(error => console.error(error.response?.status, error.response?.data));

Signal Processing

Execution Flow

  1. Receive - The webhook finds the bot by its webhook ID and checks the JSON
  2. Queue - The signal is queued and the webhook replies 202
  3. Check - The bot's status, your plan, the bot's risk limits and the position checks run
  4. Execute - The order goes to the exchange
  5. Log - The result is written to the bot's Signal Logs

Signal Results

What Signal Logs can show for a signal that was accepted but did not trade:

MessageWhat it means
Missing ticker or positionThe signal has no ticker, or neither position nor action
Unsupported signal position "..."position is not one of the values above, or an update_sl / update_tp has no valid price
Bot is not activeThe bot is paused or stopped: start it
Ignored: Already LONG (or SHORT)Futures: the bot already holds that side and DCA is off
Ignored: new entry skipped (bot is close-only: a risk limit was reached)A risk limit was reached: the bot only closes until it lifts (see Risk Management)
Rate limit: ...s remaining before next allowed signal for your tier.Your plan sets a minimum time between entry signals
No active authorized exchangesThe bot has no active exchange connection, or none matched exchange
Max DCA levels reached (...)DCA is on and its last level is already in
Signal expired after ...s (max: ...s)An entry waited too long in the queue and was dropped; closes are never dropped for age

A repeat of the same signal (same bot, ticker, exchange and position) within 3 seconds is dropped as a duplicate.

Best Practices

Security

  • Keep your webhook URL private
  • If it is exposed, create a new bot (it gets a new URL) and delete the old one
  • Use HTTPS only (HTTP not supported)

Reliability

  • Retry on 5xx errors, not on 4xx (fix the request instead)
  • Check Signal Logs to see what each signal did
  • Monitor webhook health in dashboard

Performance

  • Send only necessary fields
  • Avoid duplicate signals
  • Send currentPrice to save a price lookup

Next Steps