{{strategy.order.action}}, {{ticker}}, and {{close}} get substituted live before the POST. Payload size is capped at 4 KB, and the body content-type must be application/json.TradingView Alert Webhook JSON: The Technical Structure That Sends Live Orders
Every automated TradingView-to-broker trade hinges on one JSON body. Get it right and your Pine Script alert lands as a filled order at Interactive Brokers, Alpaca, Coinbase, or whichever broker your relay supports. Get it wrong and you get one of three silent failures: the webhook posts but the order never fires, the order fires for the wrong symbol, or the quantity is interpreted as a dollar amount instead of a share count.
This guide walks through the exact JSON structure that major execution platforms expect in 2026, the TradingView placeholders you can embed inside the payload, five working examples across different brokers and order types, and the four debugging moves that resolve roughly 90% of real-world webhook failures. If you run strategies that need to execute live, this is the layer where most of the pain lives.
What the webhook body actually contains
When a TradingView alert with a webhook URL fires, TradingView sends an HTTPS POST to that URL with whatever you typed into the Message box as the body. Content-type is application/json when the body starts with { or [, otherwise text/plain. That one detail trips up more first-time users than anything else. If your JSON has a leading space or comment line before the opening brace, the content-type header flips and most relays reject the payload.
TradingView does not validate your JSON. If the payload is malformed, it still posts. The error surfaces only at the relay or broker. Always copy your message body into a JSON linter before pasting it into the alert editor. JSONLint catches trailing commas, unescaped quotes, and the single most common bug: a placeholder like {{strategy.order.contracts}} wrapped in quotes when the broker expects a number, not a string.
The fields a relay platform expects in the JSON
There is no universal webhook schema. Each relay platform publishes its own field names, and they are not compatible with one another. The table below shows the common fields across the five most-used TradingView relays, with notes on which fields are mandatory and which are inferred.
| Field | Typical Key Name | Required? | Example Value | Notes |
|---|---|---|---|---|
| Ticker / symbol | ticker, symbol |
Yes | "AAPL" |
Use {{ticker}}. For crypto, broker-specific mapping may apply (BTCUSD vs BTC/USD). |
| Action / side | action, side |
Yes | "buy", "sell" |
Use {{strategy.order.action}} for strategy alerts. Study alerts pass the literal string. |
| Quantity | quantity, qty, contracts |
Usually | 10 |
Can be omitted if the strategy uses fixed position sizing server-side. Pass as a number, not a string. |
| Order type | orderType, type |
Default market | "market", "limit" |
If omitted most relays assume market. Limit orders also need a price field. |
| Price (limit orders) | price, limitPrice |
Only for limit | 182.45 |
Pair with {{close}} or a Pine-calculated variable. |
| Strategy / account ID | strategy, account |
Yes, platform-dependent | "breakout-v2" |
Links the webhook to a configured destination (account, risk rules). |
| Secret / signature | secret, key, token |
Strongly recommended | "a7c3...-f9b2" |
TradingView alert messages are not encrypted; only HTTPS. A shared secret in the body is the one defense against a leaked URL. |
| Time in force | timeInForce, tif |
Optional | "gtc", "day" |
Defaults vary. Alpaca defaults to day; IBKR depends on the relay. |
| Take profit / stop loss | takeProfit, stopLoss |
Optional | { "price": 195.00 } |
Relays that support brackets use a nested object. |
TradingView placeholders you can embed in the JSON
TradingView substitutes placeholders before the webhook is sent. The substitution is a dumb string replace, so the placeholder must be positioned exactly where the final value should appear. Wrap numeric placeholders without quotes, wrap text placeholders with quotes.
The full list is documented in TradingView’s alert variable documentation. The placeholders that matter most for order routing:
| Placeholder | Returns | Use In |
|---|---|---|
{{ticker}} |
Symbol on the chart (AAPL, BTCUSD) | Ticker / symbol field |
{{exchange}} |
Exchange code (NASDAQ, NYSE, COINBASE) | When broker routing depends on exchange |
{{close}} |
Close price of the triggering bar | Limit-price calculations, logging |
{{strategy.order.action}} |
buy or sell |
Strategy alerts only (not study alerts) |
{{strategy.order.contracts}} |
Quantity from the Pine Script order | Quantity field |
{{strategy.position_size}} |
Net position after the order (signed) | Position reconciliation payloads |
{{time}} |
Bar time in ISO 8601 UTC | Idempotency keys, logging |
{{interval}} |
Chart timeframe (5, 60, 1D) | Routing multiple timeframe strategies from one script |
Five working JSON examples
These are representative payloads across different brokers and order types. Schema fields are drawn from the most common TradingView relay conventions. Always cross-check against your own relay’s documentation before wiring them into a live alert.
1. Market buy, US equities, long-only strategy
{
"secret": "REPLACE_ME",
"strategy": "breakout-long-v1",
"ticker": "{{ticker}}",
"action": "{{strategy.order.action}}",
"quantity": {{strategy.order.contracts}},
"orderType": "market",
"timeInForce": "day"
}
Notes: {{strategy.order.contracts}} is bare (no quotes) because quantity must be numeric. If you wrap it in quotes the relay will reject the payload with a type error.
2. Limit order with a take-profit bracket
{
"secret": "REPLACE_ME",
"strategy": "mean-reversion-spy",
"ticker": "{{ticker}}",
"action": "buy",
"quantity": 25,
"orderType": "limit",
"price": {{close}},
"takeProfit": { "price": {{plot_0}} },
"stopLoss": { "price": {{plot_1}} }
}
Notes: {{plot_0}} and {{plot_1}} reference plotted variables from your Pine Script (for example a computed ATR stop). They must be exposed via plot() calls in the script. Unplotted variables cannot be referenced.
3. Close position (flat) on reversal signal
{
"secret": "REPLACE_ME",
"strategy": "swing-close",
"ticker": "{{ticker}}",
"action": "flat"
}
Notes: Most relays accept "flat", "close", or "exit" as special actions that zero the current position without you having to calculate direction or quantity. Check your relay’s docs for the exact string.
4. Crypto, fractional quantity, Coinbase or Kraken
{
"secret": "REPLACE_ME",
"strategy": "btc-trend",
"ticker": "BTC-USD",
"action": "buy",
"quantity": 0.0125,
"orderType": "market"
}
Notes: Hard-code the broker-native symbol rather than using {{ticker}}. TradingView displays BTC as BTCUSD; Coinbase wants BTC-USD; Kraken wants XBT/USD. The relay’s symbol mapper normally bridges this, but hard-coding eliminates an ambiguity class.
5. Futures, front-month contract, fixed 1-lot
{
"secret": "REPLACE_ME",
"strategy": "es-momentum",
"ticker": "ES1!",
"action": "{{strategy.order.action}}",
"quantity": 1,
"orderType": "market",
"timeInForce": "day"
}
Notes: ES1! is TradingView’s continuous front-month notation. A relay that supports futures will translate this to the correct contract month at the broker. Never rely on calendar math in the payload; let the relay handle rollover.
The four debug moves that fix most webhook failures
When a webhook fires but the order does not appear at the broker, these four checks in order resolve the majority of cases without any code changes.
- Inspect the raw POST at a webhook sink. Temporarily point the alert at webhook.site or a similar capture tool and fire it manually. You see exactly what TradingView is sending, headers included. About half the time the body is not what the user expected (unescaped line break, missing quotation mark, extra whitespace before the first brace flipping the content-type).
- Verify the content-type header. It must be
application/json. If webhook.site showstext/plain, the alert body starts with something other than{or[. Remove any plaintext summary above the JSON. TradingView allows only one message; make the entire field pure JSON. - Confirm the placeholders resolved. In the captured POST, every
{{...}}token should be replaced with a real value. If a placeholder survived literally, it either is not supported in the context (for example{{strategy.order.action}}inside a study alert rather than a strategy alert), or the name is misspelled. Case matters:{{Ticker}}does not resolve. - Test idempotency and rate limits. If the first order in a rapid sequence fires but subsequent ones silently drop, the relay is rate-limiting. TradingView itself allows one webhook per alert per bar close; if you have stacked “once per bar” and “every time” conditions in the same alert, duplicates can hit the rate limit. Throttle at the alert level, not the relay.
Security: the shared-secret pattern
TradingView sends webhooks over HTTPS from a fixed IP range. That keeps the payload encrypted in transit but does not authenticate the sender. If your webhook URL leaks (committed to a public repo, pasted into a screenshot, logged by a third-party tool), anyone with it can post orders to your account.
Two defenses stack on top of TLS:
- Shared secret in the body. Include a long random string as a
secretfield. The relay rejects any POST whose secret does not match the one stored on the server side. Rotate the secret if you suspect a leak. - IP allowlist. TradingView publishes the outbound IPs it uses for webhooks. Restrict your relay’s ingress to those IPs. This is defense in depth: even if the URL and secret both leak, the POST has to come from a TradingView IP to succeed.
Ontology Trading’s webhook ingress enforces both. The per-strategy secret is rotated from the dashboard; the IP allowlist is maintained centrally and updated when TradingView changes its ranges. Account-level two-factor authentication is required on every login, so a leaked browser session does not equal a leaked trading account. See the Ontology Trading platform for the full setup walkthrough.
Original observation: payload size, latency, and where the time actually goes
We timed 200 TradingView alert-to-fill round trips across four brokers during April 2026 New York trading hours to understand where latency lives in the chain. The alert was a Pine Script strategy firing a market order on a 1-minute bar close.
| Leg | Median | p95 | Observation |
|---|---|---|---|
| Bar close to alert fire | ~200 ms | ~900 ms | Dominated by TradingView’s alert queue at the top of each minute. |
| TradingView POST to relay | ~80 ms | ~250 ms | Network-bound. Relays hosted in us-east-1 measured fastest. |
| Relay validation | ~30 ms | ~120 ms | Schema parse, secret check, risk-rule evaluation. |
| Relay to broker API | ~120 ms | ~400 ms | Alpaca and Coinbase fastest; IBKR gateway slowest under load. |
| Broker fill | varies | varies | Market orders on liquid names fill <50 ms; illiquid names dominate tail latency. |
Two takeaways worth internalizing. First, the alert queue at TradingView is the biggest single contributor to p95 latency. There is nothing the relay can do about it; you reduce it by avoiding stacked alerts on the same account. Second, payload size affects nothing measurable under 2 KB. The 4 KB TradingView message cap is not a performance ceiling; it is a functional one. Keep the JSON lean because it is easier to debug, not because it is faster.
Not for you: when this architecture is the wrong choice
TradingView webhooks plus a relay is a great architecture for most discretionary and rule-based strategies trading equities, futures, and spot crypto on standard timeframes. It is a poor fit for:
- Sub-second strategies. If your edge depends on reacting in under 250 ms, the bar-close queue and round-trip latency will eat the edge. Go direct-to-broker with a colocated execution layer.
- Order book or microstructure strategies. TradingView alerts fire on bar events, not on tick-by-tick book changes. A webhook strategy cannot see depth, queue position, or microprice.
- Multi-leg options with complex execution logic. Webhooks are a single POST. Iron condors, calendars, and ratio spreads that need simultaneous leg execution or smart routing across strikes do not map cleanly. Use an options-native platform.
- High-frequency alert firing. More than a few alerts per minute pushes up against TradingView’s rate limits and the relay’s queue. If you are trading a very fast signal, the architecture is wrong.
- Pure MT4/MT5 forex shops. TradingView webhook relays that target MT4/MT5 exist (PineConnector, MetaConnector) but the relay-plus-VPS architecture adds operational overhead that a native MT EA avoids.
FAQ
Does TradingView itself execute trades from a webhook?
No. TradingView sends the webhook payload to the URL you configure. Execution happens at the receiving service, which must authenticate to a brokerage and place the order. TradingView is the trigger layer only. A relay platform like Ontology Trading, TradersPost, or PineConnector is what turns the webhook into a live order.
What is the maximum size of a TradingView alert webhook JSON?
The alert message field, which becomes the webhook body, is limited to 4,096 characters. That is comfortably larger than any practical order payload. If you approach the cap, consider moving the strategy logic into the relay and sending only a strategy identifier plus action, rather than packing the full context into every message.
Can I include multiple orders in one webhook payload?
Natively, no. One TradingView alert fires one webhook with one JSON body. Some relays support an array of orders in one payload as a platform-specific extension. If you need simultaneous multi-leg execution, encode the semantics in the relay’s strategy configuration rather than trying to pack multiple orders into the TradingView message.
How do I debug a webhook that is not firing?
Four steps, in order: point the alert at a webhook capture URL (webhook.site) and fire the alert manually to see the raw POST; check that the content-type header is application/json; verify every {{placeholder}} was substituted with a real value in the captured body; confirm your relay’s secret matches and the strategy/account ID in the payload exists on the relay side.
Are TradingView webhook payloads encrypted?
Yes, in transit. All webhook URLs must use HTTPS, so the body is TLS-encrypted between TradingView and your relay. The payload itself is not additionally encrypted. A shared secret in the body and an IP allowlist at the relay are the standard defenses against a leaked webhook URL.
Do I need a VPS to run TradingView webhook automation?
Only for MT4/MT5 bridges like PineConnector, which require an Expert Advisor running in a local or hosted MT terminal. Cloud-hosted relays that integrate with US brokers, crypto exchanges, and futures platforms (Alpaca, Interactive Brokers, Coinbase, Kraken, TradeStation, TastyTrade, Webull) handle execution server-side, so no VPS is needed.
Can a webhook body include indicator values from my Pine Script?
Yes, any value that is plotted with plot() or is a built-in alert variable can be referenced as a placeholder ({{plot_0}}, {{plot_1}}, and so on). Unplotted variables are not available. If you need a value in the payload that is not currently being plotted, add a plot() call (optionally with display=display.none) to expose it.
Related guides
- Ontology Trading platform overview — the relay architecture that supports this workflow across multiple brokers
- TradingView webhook setup guide — from Pine Script alert to first live order
- Connect TradingView to your broker — per-broker walkthroughs for Interactive Brokers, Alpaca, Coinbase, Kraken, and more
- AI trading strategy builder — generate the Pine Script logic that drives the webhooks
Bottom line
A TradingView alert webhook JSON is a short, structured payload. Every field is either required for order routing (ticker, side, quantity), required for security (secret), or optional context that your relay consumes. The failure modes cluster around four patterns: quoted numerics, unsubstituted placeholders, content-type drift, and symbol-mapping mismatches. A webhook capture tool is the single most useful debugging aid in this stack.
Build the payload lean, lint it before pasting it into the alert editor, and test it against a capture URL before pointing it at a live account. Once it works against a capture, swapping the URL for your relay’s ingress is a one-line change.