Webhook Setup
Webhooks are HTTP endpoints that receive trading signals from external sources. This guide covers everything you need to know about setting up and using webhooks.
Understanding Webhooks
A webhook is a URL that accepts incoming HTTP requests. When your signal source (TradingView, custom script, etc.) sends a request to this URL, TradeStaq processes the signal and executes the trade.
Your Signal Source → HTTP POST → Webhook URL → TradeStaq → Exchange
Your Webhook URL
Each Signal Bot has a unique webhook URL:
https://www.tradestaq.com/api/webhooks/trade/{webhookId}
Finding Your Webhook URL
- Go to Dashboard → Signal Bots
- Click on your bot
- Navigate to the Webhook tab
- Click Copy to copy the URL
Note: Keep your webhook URL private. Anyone with this URL can send signals to your bot.
Signal Templates
Minimum Required (2 fields)
The simplest signal that will work. Uses your bot's configured position size and executes at market price.
{
"ticker": "BTCUSDT",
"position": "long"
}
Recommended
Includes the current price to speed up position size calculations (reduces API calls).
{
"ticker": "BTCUSDT",
"position": "long",
"marketPrice": "97500",
"comment": "RSI oversold entry"
}
Full Control
Set every option per signal. size is in coins (0.1 BTC here), and the leverage is capped at the bot's leverage setting (see leverage below).
{
"ticker": "BTCUSDT",
"position": "long",
"size": "0.1",
"marketPrice": "97500",
"tp": "100000",
"sl": "95000",
"leverage": "10",
"comment": "Manual entry",
"exchange": "binance"
}
Field Reference
Required Fields
These fields must be present in every signal.
| Field | Type | Description | Example |
|---|---|---|---|
ticker | string | Trading symbol. Automatically normalized for your exchange. | "BTCUSDT", "BTC/USDT" |
position | string | Trade direction: long (buy), short (sell), or flat (close). action is used when position is absent | "long" |
Optional Fields
These fields customize the trade execution. If omitted, bot settings are used.
| Field | Type | Description | Default |
|---|---|---|---|
action | string | Used as the position when position is absent, with the same values (e.g. buy, sell) | - |
size | string/number | Amount in the base coin (e.g. 0.1 BTC); no percentages | Bot's configured size |
price | string/number | Limit price for a long / short entry (omit for market order) | Market order |
marketPrice | string/number | Current market price for sizing calculations | Fetched from exchange |
tp | string/number | Take profit price | None |
sl | string/number | Stop loss price | None |
leverage | string/number | Leverage for this entry, capped at the bot's leverage setting and the exchange's maximum for that coin | Bot's configured leverage |
comment | string | Note displayed in Telegram notifications | Empty |
exchange | string | Target specific exchange by name or label | All bot exchanges |
timeframe | string | Chart timeframe for validation | No validation |
strategy | string | Strategy name, recorded with the signal in Signal Logs | None |
Detailed Field Descriptions
ticker (Required)
The trading symbol for the pair you want to trade.
Accepted formats:
BTCUSDT- Simple formatBTC/USDT- With slash separatorBTC-USDT- With dash separator (auto-converted)
The system automatically normalizes the symbol for your exchange. For example, BTC/USDT becomes BTC/USDT:USDT for futures on most exchanges.
position or action (Required)
Determines the trade action to execute. Send it as position, or as action: when a signal has no position (or an empty one), its action is used in its place, with the same values and aliases. When both are sent, position wins.
| Value | Action |
|---|---|
long | Open a long position (buy) |
short | Open a short position (sell) |
flat | Close any open position |
buy | Alias for long |
sell | Alias for short |
close | Alias for flat |
TradingView Tip: Use
{{strategy.market_position}}(outputslong,short,flat) with thepositionfield, or use{{strategy.order.action}}(outputsbuy,sell) with theactionfield. On futures,sellopens a short (closing a long first), and a strategy's exit orders also sendsell, so{{strategy.market_position}}, which sendsflatfor an exit, is the safer choice.
size (Optional)
Override the bot's configured position size for this specific trade. The size is an amount of the coin you are trading (the base currency), and TradeStaq converts it to contracts on exchanges that trade in contracts. The bot's Max Position Size, when set, caps it.
Examples:
"0.1"withBTCUSDT- Trade 0.1 BTC"100"withXRPUSDT- Trade 100 XRP
Percentages are not supported: a signal whose size is not a plain number (for example "10%") is refused. To trade a share of your balance, leave size out and use percentage position sizing on the bot.
If omitted, the bot uses its configured position sizing (percentage of balance or fixed amount). On a flat signal, a size closes that many coins of the position instead of all of it.
marketPrice (Optional)
The current market price of the asset. Used internally for:
- Calculating position size when using percentage-based sizing
- Reducing API calls to the exchange
Important: This is different from price (which would trigger a limit order). marketPrice is purely informational for calculations.
tp (Optional)
Take profit price, as an absolute price. TradeStaq watches the price and closes the position at market when it reaches the take profit; no order is placed on the exchange for it.
Example: If entering long at $97,500, setting "tp": "100000" closes the long once the price reaches $100,000.
sl (Optional)
Stop loss price, as an absolute price. Like the take profit, TradeStaq watches it and closes the position at market when the price reaches it.
Example: If entering long at $97,500, setting "sl": "95000" closes the long once the price falls to $95,000.
Note: Percentages are not supported for
tpandsl:"2%"is read as a price of 2.
leverage (Optional)
The leverage for this trade, up to the bot's own leverage setting (default 1x). Only applies to futures trading.
An alert can lower the leverage, never raise it: a value above the bot's setting trades at the setting. No entry goes above the exchange's maximum for that coin either: when that is lower than the setting, the trade goes out at the exchange's maximum. To trade at a higher leverage, change the bot's leverage setting on its page.
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.
Example: with the bot set to 10x, "leverage": "5" opens the position at 5x, and "leverage": "20" opens it at 10x.
comment (Optional)
A custom note that appears in Telegram notifications. Useful for identifying why a trade was taken.
Examples:
"RSI oversold bounce""TP1 hit""Stop loss triggered"
exchange (Optional)
Target a specific exchange when your bot has multiple exchanges connected.
Matching rules:
- Matches by exchange name:
"binance","bybit" - Matches by account label:
"Main Account","DCA Account" - Case-insensitive partial matching
If omitted, the signal executes on all connected exchanges. When nothing matches, the signal fails with "No active authorized exchanges".
timeframe (Optional)
The chart timeframe the signal came from. Used for timeframe validation if enabled in your subscription tier.
Examples: "1" (1 minute), "60" (1 hour), "D" (daily)
action (Optional)
Used as the position when the signal has no position (or an empty one). It takes the same values and aliases as position, so it works with TradingView's {{strategy.order.action}} placeholder, which outputs buy or sell.
Value mapping:
buy→ Opens a long position (same aslong)sell→ Opens a short position (same asshort)
Note: If both
positionandactionare provided,positiontakes precedence.
strategy (Optional)
The strategy name that generated this signal. It is recorded with the signal, so you can see it in the signal's payload in the Signal Logs tab.
If it is the id or slug of one of TradeStaq's premium strategies that your plan does not include, the entry is refused.
Example: "strategy": "RSI Scalper" or "strategy": "Golden Cross Bot"
price (Optional)
Set a specific price to place a limit order instead of a market order. When omitted, a market order is placed.
Example: {"position": "long", "price": "95000"} places a limit order at $95,000 instead of executing at market price.
A price makes a limit order only with long or short. With buy or sell, the entry goes out at market and the price is not used as a limit. On spot, a short or sell with a price still sells the holding at market.
Note: Limit orders may not fill immediately or at all if the price doesn't reach your specified level.
Position Values Explained
| Position | What Happens |
|---|---|
long | Opens a long position. If already short, closes short first then opens long. On futures, if already long, the signal is ignored (unless DCA is on). |
short | Opens a short position. If already long, closes long first then opens short. On spot, sells the coins the bot holds. |
flat | Closes any open position without opening a new one. |
More positions (close_long, close_short, update_sl, update_tp, close_limit, close_trail, close_on_candle) are listed in the Webhook API reference. Any value not listed there is refused, and nothing is sent to the exchange.
Sending Signals
Using cURL
curl -X POST https://www.tradestaq.com/api/webhooks/trade/YOUR_WEBHOOK_ID \
-H "Content-Type: application/json" \
-d '{"ticker": "BTCUSDT", "position": "long"}'
Using Python
import requests
webhook_url = "https://www.tradestaq.com/api/webhooks/trade/YOUR_WEBHOOK_ID"
signal = {
"ticker": "BTCUSDT",
"position": "long",
"marketPrice": "97500",
"comment": "Python script entry"
}
response = requests.post(webhook_url, json=signal)
print(response.json())
Using JavaScript
const webhookUrl = "https://www.tradestaq.com/api/webhooks/trade/YOUR_WEBHOOK_ID";
const signal = {
ticker: "BTCUSDT",
position: "long",
marketPrice: "97500",
comment: "JS entry"
};
fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(signal)
})
.then(res => res.json())
.then(data => console.log(data));
Response Codes
| Code | Meaning |
|---|---|
202 | Signal received and queued for execution |
400 | Invalid JSON |
401 | Invalid signature (only for a bot with a signing secret) |
404 | Invalid webhook ID (no Signal Bot has it) |
500 | Server error |
Success Response
{
"message": "Trade Queued",
"bot": "BTC RSI Strategy"
}
A 202 means the signal was accepted, not that a trade was placed. The trade runs right after, and its result (executed, ignored, refused or failed) appears in the Signal Logs tab. A signal to a paused or stopped bot is accepted too, and then refused there with "Bot is not active".
Error Response
{
"message": "Invalid Webhook ID"
}
Signal Limits
- Duplicates: the same signal (same bot, ticker, exchange and position) sent again within 3 seconds is dropped.
- Plan interval: your plan may set a minimum time between entry signals. An entry sent sooner is refused with "Rate limit: ...s remaining before next allowed signal for your tier." Closes are never refused for this.
- Expiry: an entry that waits too long in the queue (two minutes by default) is dropped and logged as expired. Closes are never dropped for age.
Testing Your Webhook
Built-in Test Tool
- Go to your bot's detail page
- Navigate to the Webhook tab
- Your webhook URL is displayed with a copy button
- Use the Signal Logs tab to verify signals are received
Manual Testing
Test with cURL before connecting your actual signal source:
# Test long signal
curl -X POST YOUR_WEBHOOK_URL \
-H "Content-Type: application/json" \
-d '{"ticker": "BTCUSDT", "position": "long"}'
# Test close signal
curl -X POST YOUR_WEBHOOK_URL \
-H "Content-Type: application/json" \
-d '{"ticker": "BTCUSDT", "position": "flat"}'
Webhook Health Monitoring
The bot card shows webhook health based on signal activity:
| Status | Indicator | Meaning |
|---|---|---|
| Healthy | 🟢 | Signal received in last 24h |
| Warning | 🟡 | No signal in 24-48h |
| Stale | 🔴 | No signal in 48+ hours |
| New | ⚪ | Never received a signal |
Note: Monitor webhook health to ensure your signals are being received. A stale webhook may indicate an issue with your signal source.
Common Issues
"Invalid JSON"
Problem: Malformed JSON in request body
Solution: Validate your JSON at jsonlint.com
// Wrong - missing quotes
{ticker: BTCUSDT}
// Correct
{"ticker": "BTCUSDT", "position": "long"}
"Missing ticker or position"
Problem: Required fields not present
Solution: Ensure both ticker and position fields are included
"Bot is not active"
Problem: Signal sent to paused/stopped bot
Solution: Activate the bot before sending signals
"Unsupported signal position"
Problem: The position is not one the bot handles (for example hold, or a typo)
Solution: Use one of the positions in the Webhook API reference
"Rate limit: ...s remaining before next allowed signal for your tier."
Problem: Entry signals sent faster than your plan allows
Solution: Reduce signal frequency
Security Best Practices
1. Keep URL Private
- Never share your webhook URL publicly
- Don't commit it to public repositories
- Use environment variables in code
2. Regenerate If Compromised
If your webhook URL is exposed:
- Delete the bot
- Create a new bot
- Update your signal source with new URL
3. Monitor Activity
- Check activity logs regularly
- Set up Telegram alerts for trade notifications
- Review webhook health indicators