This guide walks through connecting TradingView alerts to Trading Portal: creating a webhook, configuring the alert message, and sending authenticated POST requests.
BETTER_AUTH_URL to that HTTPS origin)./app/webhook).BTC, ETH, FOREX), and optionally set asset class or allowed tickers.Your endpoint URL looks like:
POST https://your-domain.example/api/webhooks/tradingview/<webhookId>
Trading Portal validates every alert against this shape. Field names must match exactly (lowercase keys):
{
"id": "Long Take Profit",
"time": "2026-05-28T18:00:00Z",
"timenow": "2026-05-28T18:07:46Z",
"action": "sell",
"ticker": "SOLUSDT",
"price": "82.66",
"contracts": "160.45",
"position_size": "0",
"position_type": "flat",
"comment": "Long Take Profit",
"interval": "60",
"exchange": "BINANCE"
}
| Field | Required | Notes |
|---|---|---|
id | yes | Strategy or alert name; stored as strategy metadata |
time | yes | Signal time (ISO 8601) → signalAt |
timenow | yes | Ingest metadata; stored in raw payload |
action | yes | buy or sell (close semantics use position_type) |
ticker | yes | Symbol, e.g. SOLUSDT |
price | yes | String decimal |
contracts | yes | Size / quantity as string decimal |
position_size, position_type | yes | Position state for analytics |
comment, interval, exchange | yes | exchange is mapped case-insensitively (e.g. BINANCE → binance) |
TradingView can send the body as application/json or as a raw JSON string; both are accepted.
In the alert Message box, you can mix static JSON with TradingView placeholders, for example:
{
"id": "{{strategy.order.id}}",
"time": "{{timenow}}",
"timenow": "{{timenow}}",
"action": "{{strategy.order.action}}",
"ticker": "{{ticker}}",
"price": "{{close}}",
"contracts": "{{strategy.order.contracts}}",
"position_size": "{{strategy.position_size}}",
"position_type": "{{strategy.market_position}}",
"comment": "{{strategy.order.comment}}",
"interval": "{{interval}}",
"exchange": "{{exchange}}"
}
Adjust placeholders to match your strategy; the server still requires all keys listed above after TradingView substitutes values.
TradingView webhook alerts do not support custom request headers. Every request must include your webhook secret as a query parameter on the URL:
https://your-domain.example/api/webhooks/tradingview/YOUR_WEBHOOK_ID?secret=YOUR_SECRET
Trading Portal also accepts X-Webhook-Secret and Authorization: Bearer <secret> for curl/proxy tests, but TradingView users should paste the URL with ?secret=....
Requests with a missing or wrong secret receive 401 Invalid webhook secret.
?secret=YOUR_SECRET./app/trades) and confirm a new row appears.curl from your machine (replace URL, secret, and JSON):curl -sS -X POST "https://your-domain.example/api/webhooks/tradingview/YOUR_WEBHOOK_ID?secret=YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{
"id": "Manual test",
"time": "2026-05-28T18:00:00Z",
"timenow": "2026-05-28T18:07:46Z",
"action": "buy",
"ticker": "SOLUSDT",
"price": "82.66",
"contracts": "1",
"position_size": "1",
"position_type": "long",
"comment": "curl test",
"interval": "60",
"exchange": "BINANCE"
}'
Success (200):
{ "ok": true, "tradeId": "trade_..." }
Duplicate alert (idempotent retry):
{ "ok": true, "tradeId": "trade_...", "duplicate": true }
| Status | Meaning |
|---|---|
| 200 | Trade stored (or duplicate acknowledged) |
| 400 | Invalid JSON / schema / ticker not on allowlist — body includes issues when validation fails |
| 401 | Invalid or missing secret |
| 404 | Unknown or inactive webhook ID |
| 429 | Rate limit exceeded — retry after Retry-After seconds |
| 500 | Server error — contact support if persistent |
Create separate webhooks per asset or strategy (e.g. BTC, ETH, FOREX). Each has its own URL, secret, optional ticker allowlist, and trade history dimension in analytics.
?secret=... to git or share them in public channels.