β‘οΈConnect TradingView via Webhook
The TradingView integration via Webhook is in beta. Please use it with a demo account to ensure everything works as expected.
Webhooks require some technical knowledge of JSON formatting and general web request concepts. If you are not familiar with these topics, we recommend using the more straightforward solution of connecting TradingView with a supported broker directly.
TradingView webhooks allow you to send automated trading alerts directly to external systems. By connecting them to MetaCopier, you can automatically execute and copy trades based on TradingView alerts and Pine Scripts without manual intervention. This guide shows how to set up and use TradingView webhooks with MetaCopier.
What is webhook? A webhook is a way for one platform to automatically send information to another platform in real time.
In the case of TradingView and MetaCopier, a webhook allows TradingView to send a message to MetaCopier whenever an alert is triggered. This message can contain trading instructions such as open a trade, close a trade, or modify a position. MetaCopier receives the message and executes the action on the connected trading account automatically.
In simple terms, a webhook acts like a messenger that instantly delivers TradingView alerts to MetaCopier so trades can be executed automatically.
Requirements
To use TradingView webhooks with MetaCopier, you need the following:
One trading account connected to MetaCopier
A TradingView account
Quick Start
Enable the Feature
On the trading account where you want positions to be opened or closed, add the βTradingView Webhookβ feature in MetaCopier:

A new window with the TradingView Webhook configuration will open. For now, leave the default settings and save them. Each setting is explained in the Advanced Guide below.

Configure a New Alert
Open the TradingView webhook feature (edit button) and select the Setup Guide at the top.

A new window will open where you will find all the information required for the TradingView webhook.

In TradingView, open the desired chart (in this example, XAUUSD). Then, in the top-right corner, open the Alerts section and create a new alert with the "+" symbol.

A new window will open. The first step is to define the Webhook URL, which is where the alerts will be sent. Open the Notifications tab and enter the URL shown in the MetaCopier Setup Guide into the Webhook URL field.

Switch to the Message tab in TradingView, where you can define how the message sent to MetaCopier will be formatted. The message must be formatted as JSON and includes the instructions for MetaCopier. Below is a simple example that opens a buy position for XAUUSD with 0.1 lot size.
In TradingView, it will look like this. Please make sure that the rectangle containing the JSON message is green. If it is orange, it means the JSON contains formatting errors.

Thatβs all! Click Create to save the alert and make sure it is active in TradingView.

Once the alert is triggered, MetaCopier will receive the notification and the defined order will be executed on your trading account.

In the Log section in TradingView, you can check the delivery status.

And this is how it looks on the trading account after the webhook has been received.

Webhook examples
Below are some typical JSON messages to help you set up your alerts correctly. As a starting point, we will use the example shown earlier:
To avoid specifying the symbol every time (for example, if you want to reuse the same format on multiple alerts or charts), you can use TradingView placeholders. These placeholders act like variables that TradingView automatically fills with the correct values when the alert is triggered, so you donβt need to hardcode them.
Letβs use the {{ticker}} placeholder to avoid defining the symbol name in every alert:
When the alert is triggered, the symbol will automatically be replaced based on the chart used to create the alert (in our case, XAUUSD).
Now letβs define take profit (TP) and stop loss (SL) values.
This works, but as you can imagine, the TP/SL values are hardcoded and must be defined each time.
Using Points Instead of Price
By default, stopLoss and takeProfit are interpreted as absolute price levels. You can also specify them as a distance in points from the fill price by adding stopLossType and/or takeProfitType:
In this example, the SL is set 500 points below the fill price and TP is set 1000 points above (for a buy order). This is useful when you don't know the exact entry price in advance.
How SL/TP reach your broker: separateTpSlOrder
MT4 and MT5 do not support relative (points based) SL/TP at the platform level, so MetaCopier resolves them for you. The optional separateTpSlOrder flag controls how:
separateTpSlOrder: false (default)
SL and TP are always sent together with the order, so the position is never held unprotected.
With
pricethe levels are used exactly as you send them.With
pointsMetaCopier fetches the current quote, calculates the levels from it, and sends them with the order. Once the real fill price is known, a follow up modify corrects the levels so the distance matches your request exactly even after slippage.If the levels are invalid (for example inside the broker's minimum stop distance), the broker rejects the whole order and no position is opened. You receive a clear error and the request is retried.
If no quote is available for the symbol, the position is not opened and the request fails with
QUOTE_MISSING.
separateTpSlOrder: true
The order is sent without SL/TP and the levels are attached afterwards through a separate modify order. This applies to both price and points.
The position always opens, even when the levels are invalid.
The modify is not guaranteed to succeed. If the broker rejects it (minimum stop distance, freeze level), the position stays open without SL/TP.
Also note that points means broker points (the smallest price increment of the symbol), not pips. On a 3 digit gold quote one point equals 0.001, so "stopLoss": 400 is only $0.40 away from the entry price, which most brokers reject as too close.
Multiple Take Profits in a Single Alert (native multi-TP)
If your strategy ladders out at several TP levels, you can send them in one webhook call using the takeProfits array. MetaCopier expands the request server-side into one position per TP level - atomically, in order, and without any risk of bursts being dropped by the broker.
In this example MetaCopier opens 3 positions, each with the same SL but a different TP, splitting the parent volume equally (0.02 each). Each leg gets its own unique tradeKey automatically (xau_long_001_t1, xau_long_001_t2, β¦) so you can later modify or close them individually.
Per-leg sizing. Each entry in takeProfits may override the default equal split:
volume- absolute lot size for that leg.volumePercent- percentage of the parent sizing (works withvolume,riskPercent,riskAmount, ormarginPercent). Sum of percents must be β€ 100.Omitted - receives an equal share of whatever sizing remains.
Risk-based / margin-based parents. When the parent uses riskPercent / riskAmount / marginPercent and the legs do not override sizing, the sizing is divided equally across legs so the total equals what you requested.
Per-leg type. A leg may set its own takeProfitType (price or points); otherwise it inherits from the parent.
Constraints.
Maximum 20 take profit levels per request.
When using
takeProfits, the parenttradeKeymust be β€ 16 characters (MetaCopier appends_t<index>to derive unique per-leg keys within the 20-char limit).The HTTP response stays backward compatible: the top-level
requestIdis the first leg's id, anddata.subRequestIdslists every leg id for per-leg status tracking viaGET /requests/{requestId}/status.
Why use this instead of sending multiple webhooks? A single request avoids the race between concurrent webhook calls hitting the broker. Each leg is reserved with a unique tradeKey and submitted through the same queue, so partial drops under bursts no longer happen.
To make them dynamic, you have two options:
Use the MetaCopier TP/SL Management feature to set TP/SL values automatically after the order has been placed on the broker.
Use Pine Script in TradingView to calculate these values dynamically and include them in the webhook message.
Letβs now see how to manage existing trades. To be able to modify or close existing trades via webhook, we first need to define a unique identifier when opening a position. This is done using the JSON property tradeKey. For example:
To modify a specific position, you can create an alert with the following content:
And to close it, you can use:
Webhook URL
MetaCopier operates in four regions: New York, London, Berlin, and Singapore. Each region has its own trading API to help minimize latency and improve execution speed.
In the Setup Guide described above, the correct Webhook URL is automatically generated for your trading account and region.
The Webhook URL has the following structure:
New York
api-newyork
London
api-london
Berlin
api-berlin
Singapore
api-singapore
Global
api
Advanced Guide
This section covers all features, configuration options, and advanced usage.
Feature Configuration
All configuration options for the TradingView Webhook feature:
Configuration Reference
enableWebhook
boolean
true
Enable/disable webhook processing
authMethod
string
SECRET
SECRET or HMAC
webhookSecret
string
-
Secret for SECRET auth (min 16, max 64 chars)
hmacSecret
string
auto
Secret for HMAC auth (auto-generated, read-only)
allowedActions
array
all
Allowed actions. Empty = all allowed
allowCloseAll
boolean
false
Enable closeAll action
allowSymbolOnlyClose
boolean
false
Allow close by symbol without filters
maxMatchCount
integer
3
Max positions before requiring force: true (1-100)
ipAllowlist
array
[]
Allowed IPs. Empty = all allowed
requireTimestampForSecret
boolean
false
Require timestamp for SECRET auth
timestampToleranceSeconds
integer
60
Max age of timestamp in seconds (10-300)
dataRetentionDays
integer
30
TTL for stored data (1-90 days)
maxAllowedVolume
number
0
Max volume in lots per trade (safety cap). Applies to all sizing modes (volume, riskPercent, riskAmount, marginPercent). 0 = deactivated (no cap)
openRetry
boolean
true
Retry a request that was rejected by the broker or left unanswered by the terminal. false = send once
openRetryTimeoutInMinutes
integer
5
Total retry window in minutes (1-60). Retries run every 30 seconds. Only used if openRetry is true
Retry Behaviour
A webhook request is not always answered immediately by the broker. The trading terminal waits up to 15 seconds for a confirmation. If nothing arrives within that time, or if the broker rejects the order (for example because the market is momentarily closed or the price moved away), MetaCopier can retry the request automatically.
Retries run every 30 seconds until
openRetryTimeoutInMinuteshas elapsed.Retries that follow a missing broker confirmation reuse the same internal request ID, so a trade that did reach the broker is never opened twice.
Once the window has elapsed, the request is marked as failed and a warning entry appears in the account logs.
With
openRetry: falsethe request is sent exactly once. This is the recommended setting for scalping and high-frequency strategies, where a fill two minutes late is worse than no fill at all.
The webhook response (202 Accepted) is returned immediately when the alert arrives. Retries happen asynchronously in the background, so TradingView never has to wait.
Authentication Methods
SECRET Authentication (Recommended)
Simple secret in the request body:
Optional Replay Protection
Enable requireTimestampForSecret: true to require timestamp:
Requests with timestamps older than timestampToleranceSeconds are rejected.
HMAC Authentication (Advanced)
For enhanced security using cryptographic signatures:
Signature Calculation:
Where:
timestamp= Unix seconds (required, must be numeric)canonicalPayload= JSON with sorted keys, no whitespace, excludingtimestampandsignaturefields
Note: HMAC auth requires a proxy service to compute the signature before sending to MetaCopier.
All Actions
open
Open a new position
close
Close position(s) by matching criteria
cancelOrder
Cancel pending order(s) ONLY (never touches live positions)
modify
Update SL/TP or partial close
closeAll
Close all positions (requires allowCloseAll: true)
store
Store custom data in Database
Open Action
Opens a new position.
Open Fields
symbol
β
string
Trading pair (e.g., EURUSD)
orderType
β
string
Order type (see below)
volume
β‘
number
Lot size (must be positive). Required unless riskPercent, riskAmount, or marginPercent is used
riskPercent
β‘
number
Risk as percentage of account balance (e.g., 1.0 = 1%). Requires stopLoss. See Risk Per Trade Sizing
riskAmount
β‘
number
Risk as fixed currency amount (e.g., 100 = $100). Requires stopLoss. See Risk Per Trade Sizing
marginPercent
β‘
number
Size the position to use a percentage of your free (available) margin (e.g., 5.0 = 5%). Does not require a stop loss. See Margin-Based Sizing
stopLoss
β¬
number
Stop loss value (interpretation depends on stopLossType)
stopLossType
β¬
string
price (default) for absolute price, points for relative distance from fill price
takeProfit
β¬
number
Take profit value (interpretation depends on takeProfitType)
takeProfitType
β¬
string
price (default) for absolute price, points for relative distance from fill price
separateTpSlOrder
β¬
boolean
false (default): SL/TP are sent together with the order. true: the order is opened first and SL/TP are attached through a separate modify order, which the broker may reject. See the note in the Points section
takeProfits
β¬
array
Optional list of TP levels for native multi-TP. When provided, MetaCopier opens one position per level atomically. See Multi Take Profit
openPrice
β¬
number
Entry price (for pending orders)
pendingExpirySeconds
β¬
number
Native broker-side expiry (seconds from now) for pending orders (buyLimit/sellLimit/buyStop/sellStop) on MT4/MT5. The broker cancels the order automatically if it is not filled in time. Ignored for market orders and unsupported account types. 0/omitted = good-till-cancelled. See Pending Order Expiry
tradeKey
β¬
string
Unique identifier for this trade (max 20 chars, no `
magicNumber
β¬
string
Group identifier for strategy
orderId
β¬
string
Strategy order ID from {{strategy.order.id}} (no `
comment
β¬
string
Trade comment (no `
Comment Truncation: MetaCopier prepends a short tracking prefix to the comment field (format: TV|tradeKey|orderId|comment). Since MT4/MT5 brokers typically limit the comment field to 25β31 characters, your comment may be truncated depending on the length of tradeKey and orderId. To maximize space for your comment, use short tradeKey values or omit orderId. If you don't need trade tracking via comment, you can also omit tradeKey and use magicNumber for position management instead - in that case, only your comment will appear (prefixed with TV|).
Pipe character restriction: The tradeKey, orderId, and comment fields must not contain the pipe character (|). This character is used internally as a delimiter for position tracking. Requests containing | in these fields will be rejected with a 400 error.
Order Types
buy
Market buy
sell
Market sell
buylimit
Buy limit order
selllimit
Sell limit order
buystop
Buy stop order
sellstop
Sell stop order
Order types are case-insensitive.
Risk Per Trade Sizing
Instead of specifying a fixed volume, you can let MetaCopier automatically calculate the lot size based on your risk tolerance and the stop loss distance. Two modes are available:
riskPercent- risk a percentage of your account balance per traderiskAmount- risk a fixed currency amount per trade
How It Works
When you send riskPercent or riskAmount instead of volume, MetaCopier calculates the lot size using these formulas:
Percentage mode:
Amount mode:
The result is then rounded to the symbol's lot step and clamped to the symbol's min/max volume.
Volume cap applies here too. If you set maxAllowedVolume (see Configuration Reference) to a value greater than 0, the calculated lot size is capped to it after the risk calculation. Set it to 0 to deactivate the cap.
Requirements
To use riskPercent or riskAmount, the following features must be enabled on your trading account in MetaCopier:
TradingView Webhook feature
Risk Per Trade feature (provides tick value configuration and symbol settings)
The Risk Per Trade feature is needed for the tick value used in the lot size calculation. Tick values are collected automatically from your trades once both features are active.
You do not need to set a risk percentage or absolute risk amount in the Risk Per Trade feature settings. Both values can be left at 0 - this disables the account-level risk limiting, but the tick value service still runs in the background. The webhook uses its own riskPercent or riskAmount parameter for lot size calculation, and only needs the tick value data from the Risk Per Trade feature.
Tick value can also be entered manually. On the account-level Risk Per Trade feature you can either keep Tick value automatic adjustement enabled (the default, detects the tick value from live and history trades) or disable it and type the Tick value in directly, globally or per symbol. Use manual entry if you want to trade immediately without waiting for auto-detection, or when auto-detection is unreliable (very small or very few trades). See Risk Per Trade - Tick Value for how to calculate it.
Important: When automatic detection is used, the tick value service needs data from at least one closed or open trade before it can calculate lot sizes. The trades must have some pips of profit or loss (not zero) so the system can detect the tick value in your account currency. If no tick value data is available yet and no manual tick value is configured, the webhook will return a RISK_TICK_VALUE_UNAVAILABLE error.
Rules
volume,riskPercent,riskAmount, andmarginPercentare mutually exclusive - provide exactly oneriskPercentmust be greater than0and at most100riskAmountmust be greater than0stopLossis mandatory when usingriskPercentorriskAmount(the SL distance determines the lot size). It is not required formarginPercentWorks with both
stopLossType: "price"andstopLossType: "points"Works with all order types (market and pending)
Example: Risk 1% of Balance
If your account balance is $10,000, this risks $100 (1%). With a 50-point SL and the current tick value, MetaCopier calculates the appropriate lot size automatically.
Example: Risk 2% with Price-Based SL
Example: Risk $100 Fixed Amount
This risks exactly $100 regardless of your account balance. With a 50-point SL and the current tick value, MetaCopier calculates the appropriate lot size automatically.
Pine Script Example with Risk Per Trade
Margin-Based Sizing
Instead of sizing from a stop-loss distance, you can size the position from your free (available) margin using marginPercent. This is useful when your strategy has no fixed stop loss, or when you want each trade to consume a predictable slice of your buying power.
How It Works
When you send marginPercent instead of volume, MetaCopier calculates the lot size using:
marginPerLot is the margin required for 1.0 lot, taken directly from the broker (MT4 MODE_MARGINREQUIRED / MT5 OrderCalcMargin) when available, otherwise derived from the current price, contract size, and the symbol's effective leverage. The result is rounded to the symbol's lot step and clamped to its min/max volume.
Self-limiting. Because sizing is based on free margin, each new open position reduces the margin available to the next one, so trades are automatically sized smaller as your exposure grows - reducing the chance of a margin call.
No stop loss and no Risk Per Trade feature required. Unlike riskPercent / riskAmount, margin-based sizing does not use the stop-loss distance or the tick value, so the Risk Per Trade feature is not needed.
Rules
marginPercentis mutually exclusive withvolume,riskPercent, andriskAmount- provide exactly onemarginPercentmust be greater than0and at most100No
stopLossis requiredWorks with all order types (market and pending)
The
maxAllowedVolumecap (if set) still applies after the calculation
Not available where margin is unknown. Some account types (e.g. certain crypto/CEX accounts) do not report free margin. On those accounts a marginPercent request is rejected with a MARGIN_UNAVAILABLE reason.
Example: Use 5% of Free Margin
If your free margin is $10,000 and 1.0 lot of EURUSD requires $500 of margin, this opens (10000 Γ 5 / 100) / 500 = 1.0 lot.
Multi Take Profit
Instead of sending several webhook calls when your strategy ladders out at multiple TP levels, you can declare every level in a single open request using the takeProfits array. MetaCopier expands the request server-side into one position per TP level, atomically and in order, so bursts cannot be partially dropped by the broker.
In this example MetaCopier opens 3 positions, each sharing the same SL but with a different TP, splitting the parent volume equally (0.02 each). Each leg receives its own unique tradeKey derived from the parent (xau_long_001_t1, xau_long_001_t2, β¦), so legs can later be modified or closed individually.
Level Fields
Each entry in takeProfits accepts the following fields:
takeProfit
β
number
TP value for this leg (price or points depending on takeProfitType)
takeProfitType
β¬
string
price (default) or points. If omitted, inherits the parent request's takeProfitType
volume
β¬
number
Absolute lot size for this leg. Mutually exclusive with volumePercent
volumePercent
β¬
number
Percentage (0-100) of the parent sizing to allocate to this leg. Mutually exclusive with volume. Works with parent volume, riskPercent, riskAmount, and marginPercent
If a leg sets neither volume nor volumePercent, it receives an equal share of whatever sizing remains after the explicit allocations.
Per-Leg Sizing Example
The first leg takes a fixed 0.03 lots, the second takes 33.33% of the parent sizing, and the third receives the remainder.
Risk-Based / Margin-Based Parents
When the parent uses riskPercent, riskAmount, or marginPercent and the legs do not override sizing, the sizing is divided equally across legs so the total equals what you requested. Per-leg volumePercent can still be used to weight legs differently.
Constraints
Maximum levels per request
20
Parent tradeKey length
β€ 16 chars when takeProfits is used (server appends _t<index> to derive unique per-leg keys within 20 chars)
Sum of volumePercent across legs
β€ 100
Per-leg takeProfit
Required on every entry
volume vs volumePercent
Mutually exclusive per leg
Response Shape
The HTTP response stays backward compatible:
The top-level
requestIdis the first leg's request id.data.subRequestIdslists every leg id in order.data.legCountis the total number of legs created.
Use the leg ids with GET /requests/{requestId}/status to track per-leg delivery and execution.
Managing Legs After Open
Each leg behaves like a normal position once opened. To modify or close a specific leg, use its derived tradeKey:
To act on all legs at once, group them with a shared magicNumber on the parent request and use matchMode: GROUP:
Why use this instead of sending multiple webhooks? A single request avoids the race between concurrent webhook calls hitting the broker. Each leg is reserved with a unique tradeKey and submitted through the same queue, so partial drops under bursts no longer happen.
Close Action
Closes position(s) based on matching criteria.
Match Modes
EXACT
tradeKey
Close specific position(s) from stored mapping
GROUP
magicNumber or orderId
Close positions by strategy group
BULK
symbol
Close all positions for a symbol
If matchMode is not provided, it's auto-detected based on which fields you include.
An explicit matchMode overrides auto-detection and the other identifiers are ignored. If you send "matchMode": "GROUP" together with a tradeKey, the tradeKey is not used at all and only magicNumber / orderId decide which positions match. If nothing matches you get POSITION_NOT_FOUND, even though the tradeKey exists.
To match a single position by its tradeKey, either omit matchMode entirely or set it to "EXACT".
Close by TradeKey (EXACT)
Close by Magic Number (GROUP)
Close by Symbol (BULK)
Close Fields
matchMode
string
EXACT, GROUP, or BULK (auto-detected if omitted). An explicit value overrides auto-detection
tradeKey
string
Position identifier (EXACT mode). Ignored if matchMode is GROUP or BULK
magicNumber
string
Strategy identifier (GROUP mode)
orderId
string
Strategy order ID (GROUP mode)
symbol
string
Trading pair (BULK mode)
direction
string
long or short filter (BULK mode)
closeMode
string
first, last, or all (default: all)
force
boolean
Allow closing more than maxMatchCount positions
Close Modes
first
Close oldest position (FIFO)
last
Close newest position (LIFO)
all
Close all matching positions
Force Flag
If more than maxMatchCount positions match, you must either:
Add
force: truewith explicitmatchModeAdd more specific filters
This prevents accidental bulk operations.
Cancel Order Action
Cancels pending order(s) only (unfilled Limit/Stop orders). Live (already filled) positions are never affected. Uses the exact same matching options as close (tradeKey / magicNumber / orderId / symbol + direction / closeMode / matchMode).
Why this exists. If you manage pending-order expiry with your own timer and send close when it fires, a close would also close the position if the order was already filled in the meantime. cancelOrder removes that risk: it only ever cancels pending orders. If the order already filled (or no longer exists), the request is a safe no-op (success, nothing cancelled) rather than an error.
Cancel by TradeKey (EXACT):
Cancel a pending order for a symbol (BULK):
cancelOrder is a distinct action string. If you restrict allowedActions, add "cancelOrder" to the list (leaving allowedActions empty allows all actions).
Native alternative: For MT4/MT5 you can skip the external timer entirely by setting pendingExpirySeconds on the open payload. See Pending Order Expiry.
Pending Order Expiry
Set pendingExpirySeconds on an open request to give a pending order (buyLimit, sellLimit, buyStop, sellStop) a native broker-side expiry. The broker cancels the order automatically if it has not been filled within that time. No follow-up webhook is needed.
Only applies to pending orders on MT4/MT5. It is ignored for market orders (
buy/sell) and for account types that do not support broker-native expiry.0or omitted means good-till-cancelled (no expiry).Enforcement is broker-dependent: some brokers require a minimum expiry (often at least a few minutes) or do not allow pending order expiry at all. If the broker rejects the expiry, the order is placed without one.
Because the broker owns the timer, expiry works even if it fires long after the alert; there is no race with a fill (a filled order simply stays open).
Prefer this over an external timer +
cancelOrderwhen your account is MT4/MT5. UsecancelOrderfor manual/early cancellation or on connectors without native expiry.
Modify Action
Modifies existing position(s). Supports EXACT (tradeKey), GROUP (magicNumber / orderId), and BULK (symbol) matching - same modes as the close action.
Modify a single position by tradeKey (EXACT):
Modify all positions sharing a magicNumber (GROUP):
Modify all positions sharing a strategy orderId (GROUP):
Modify all open positions on a symbol (BULK):
If a modify request matches more than maxMatchCount positions, the request is rejected with AMBIGUOUS_MATCH. Add force: true together with an explicit matchMode to proceed. This safety guard mirrors the close action.
Partial Close
If reduceVolumeBy reduces the position to 0 or below, the position is fully closed.
reduceVolumeBy is only supported in EXACT mode (matching by tradeKey). It is rejected in GROUP and BULK modes because "reduce by X" is ambiguous across multiple positions (per-position vs. total group exposure). To reduce volume for several positions, send one modify per tradeKey.
Modify Fields
matchMode
string
EXACT, GROUP, or BULK (auto-detected). An explicit value overrides auto-detection
tradeKey
string
Position identifier (EXACT mode). Ignored if matchMode is GROUP or BULK
magicNumber
string
Strategy identifier (GROUP mode)
orderId
string
Strategy order ID (GROUP mode)
symbol
string
Trading pair (BULK mode)
force
boolean
Allow modifying more than maxMatchCount positions
stopLoss
number
New stop loss price (absolute price only, not points)
takeProfit
number
New take profit price (absolute price only, not points)
openPrice
number
New price for pending orders
reduceVolumeBy
number
Volume to reduce (partial close)
CloseAll Action
Closes ALL positions on the account.
Requirements:
Feature must have
allowCloseAll: trueRequest must have
force: true
This closes every open position on the account!
Store Action
Stores custom data from TradingView strategies/indicators.
data
β
object
Any JSON object to store (max 100KB size)
Data is stored in Database with TTL based on dataRetentionDays.
The data object has a maximum size limit of 100KB. Requests exceeding this limit will be rejected.
Retrieve Stored Data
Use the REST API to fetch stored data:
List all stored data (paginated):
Response:
Get specific data by ID:
Delete specific data:
These endpoints require API authentication (not the webhook secret). See REST API documentation for details.
Common Request Fields
Fields available on all actions:
action
string
Action type (required)
secret
string
Webhook secret (for SECRET auth)
signature
string
HMAC signature (for HMAC auth)
timestamp
number/string
Unix seconds or ISO-8601 string
idempotencyKey
string
Prevents duplicate execution
schemaVersion
integer
Schema version (only 1 supported)
Idempotency
Include an idempotencyKey to prevent duplicate executions:
Same key within 5 minutes returns the cached response.
Timestamp Format
Timestamp accepts:
Number: Unix seconds (e.g.,
1708771200)String: ISO-8601 (e.g.,
"2024-02-24T12:00:00Z")
Error Codes
Authentication Errors (401)
INVALID_SECRET
Webhook secret doesn't match
INVALID_SIGNATURE
HMAC signature verification failed
TIMESTAMP_EXPIRED
Timestamp outside valid window
TIMESTAMP_MISSING
Timestamp required but not provided
Authorization Errors (403)
WEBHOOK_NOT_ENABLED
Feature not enabled on account
IP_NOT_ALLOWED
Request IP not in allowlist
ACTION_NOT_ALLOWED
Action not in allowed actions list
CLOSE_ALL_NOT_ALLOWED
closeAll requires allowCloseAll: true
SYMBOL_ONLY_NOT_ALLOWED
Symbol-only close requires additional filter
PROFIT_TARGET_HIT
Order skipped - a profit target is hit
RISK_LIMIT_HIT
Order skipped - a risk limit is hit
PROFIT_TARGET_AND_RISK_LIMIT_HIT
Order skipped - both profit target and risk limit are hit
Validation Errors (400)
INVALID_ACTION
Unknown or missing action
INVALID_JSON
JSON parsing failed
INVALID_CONTENT_TYPE
Must be application/json
INVALID_ORDER_TYPE
Unknown order type
INVALID_MATCH_MODE
Unknown matchMode (must be EXACT/GROUP/BULK)
MISSING_IDENTIFIER
No position identifier provided
FORCE_REQUIRES_EXPLICIT_MODE
force:true requires explicit matchMode
UNSUPPORTED_SCHEMA_VERSION
Only schemaVersion 1 supported
INVALID_TIMESTAMP_TYPE_FOR_HMAC
HMAC requires numeric timestamp
INVALID_RISK_PERCENT
riskPercent must be > 0 and β€ 100
INVALID_RISK_AMOUNT
riskAmount must be > 0
INVALID_MARGIN_PERCENT
marginPercent must be > 0 and β€ 100
RISK_SIZING_CONFLICT
Only one of volume, riskPercent, riskAmount, or marginPercent can be specified
RISK_PERCENT_REQUIRES_STOP_LOSS
stopLoss is mandatory when using riskPercent
RISK_AMOUNT_REQUIRES_STOP_LOSS
stopLoss is mandatory when using riskAmount
MISSING_SIZING
None of volume, riskPercent, riskAmount, or marginPercent provided
RISK_PER_TRADE_FEATURE_REQUIRED
Risk Per Trade feature must be added to the account
RISK_TICK_VALUE_UNAVAILABLE
No tick value data available yet for the symbol see Risk Per Trade Sizing
Not Found Errors (404)
TRADEKEY_NOT_FOUND
TradeKey not found in mapping
POSITION_NOT_FOUND
No positions match criteria
ACCOUNT_NOT_FOUND
Account ID not found
Conflict Errors (409)
AMBIGUOUS_MATCH
Too many matches - add force:true with explicit matchMode
Service Errors (503)
ACCOUNT_NOT_CONNECTED
Trading account is disconnected
IP Allowlist (Optional)
Restrict webhook access to specific IPs:
TradingView IPs may change without notice. Empty allowlist (default) allows all IPs.
Troubleshooting
When troubleshooting any webhook issue, check the Logs and Audit Logs sections in MetaCopier. Logs show real-time information about trade execution, errors, and broker rejections. Audit Logs provide a detailed history of all actions and changes, helping you understand the sequence of events that led to an issue.
Alert not working?
Check your webhook URL is correct
Verify your JSON is valid (use a JSON validator)
Confirm your secret matches exactly
Make sure your account is connected
Position not found?
Check the
tradeKeyspelling exactlyThe position may already be closed
Use the exact same
tradeKeyyou used when opening
AMBIGUOUS_MATCH error?
Add
force: truewith explicitmatchModeOr add more specific filters (symbol, direction)
HMAC signature fails?
Ensure timestamp is numeric (Unix seconds)
Ensure canonical payload excludes timestamp/signature
Ensure keys are sorted alphabetically
Alert accepted (202) but no trade appears?
The webhook was queued successfully, so the problem is on the broker side. Check the account Logs for the rejection reason.
If the log shows that no confirmation was received from the terminal, the order is retried automatically as long as
openRetryis enabled. IncreaseopenRetryTimeoutInMinutesif your broker is regularly slow.If
openRetryis disabled, the request is sent only once and a warning entry is written immediately.A message such as
Retry window elapsed after N attempt(s)means every attempt inside the configured window failed. In that case the underlying broker error in the same log entry is the relevant one.
Examples by Use Case
This section provides complete examples for common trading scenarios.
Close All Positions on Account
Close every open position on the account. Useful for emergency exit or end-of-day cleanup.
Step 1: Enable closeAll in Feature Settings
Step 2: Send closeAll Request
This closes ALL positions immediately. Both allowCloseAll: true and force: true are required as safety guards.
Close by Strategy Group (Magic Number)
Close all positions belonging to a specific strategy. Useful when running multiple strategies on the same account.
Open with Magic Number
Close All Positions with Same Magic Number
This closes ALL positions with magicNumber: "RSI_Strategy_15M", regardless of symbol or direction.
Close Only Long Positions in Group
Close by Order ID (Pine Script Strategies)
Close positions by strategy entry name. Useful for Pine Script strategies using strategy.entry().
Pine Script Strategy Example
Alert Message (Open)
Alert Message (Close All "Long Entry" Positions)
orderId is NOT unique - all positions with the same entry name are closed.
Close by Symbol (Bulk Matching)
Close positions for a specific symbol. Requires additional filters by default.
Close All EURUSD Long Positions
Close All EURUSD Short Positions
Close ALL EURUSD Positions (Both Directions)
Without direction, this matches all EURUSD positions. If more than maxMatchCount positions exist, force: true is required.
Close First or Last Position (FIFO/LIFO)
Close only the oldest or newest position matching your criteria.
Close Oldest Position (FIFO)
Close Newest Position (LIFO)
Close Oldest Position in Strategy Group
Partial Close (Reduce Position Size)
Reduce position size without fully closing it.
Example: Position is 0.1 lots β reduceVolumeBy: 0.05 β Position becomes 0.05 lots
Partial Close by Magic Number
This reduces ALL positions in the group by 0.01 lots each.
Using the Force Flag
The force flag allows closing more positions than maxMatchCount (default: 3).
When Force is Required
2 positions match, maxMatchCount=3
No
5 positions match, maxMatchCount=3
Yes
closeAll action
Always
Symbol-only close without direction
Yes
Force with Explicit matchMode
Important: force: true requires an explicit matchMode. Auto-detected matchMode with force will be rejected with FORCE_REQUIRES_EXPLICIT_MODE.
Real-World Strategy Examples
Grid Trading Strategy
Open multiple positions with the same magic number, close oldest first:
Open (multiple grid levels)
Close Oldest Grid Position (Take Profit)
Close All Grid Positions (Emergency Exit)
Multi-Symbol Strategy
Trade multiple symbols with the same strategy:
Open Position
Close Specific Symbol
Close All Strategy Positions (All Symbols)
Scalping Strategy with Take Profit Levels
Open with tradeKey for precise control:
Open Position
TradingView placeholders don't support math operations. Use fixed prices or calculate SL/TP in your Pine Script using strategy.order.alert_message.
Partial Close at First Target (1/3)
Move Stop Loss to Break Even
Tip: For dynamic SL/TP based on entry price, use strategy.order.alert_message in your Pine Script to pass calculated values.
Close Remaining Position
Symbol-Only Close (Advanced)
Close all positions for a symbol without direction filter. Requires special permission.
Step 1: Enable in Feature Settings
Step 2: Close All Symbol Positions
Note: Without allowSymbolOnlyClose: true, you must include direction or another filter.
Using Dynamic Values (Advanced Pine Script)
TradingView placeholders don't support math operations. To use calculated values (like dynamic SL/TP), use the alert_message parameter in your Pine Script.
Pine Script Example:
Alert Message (uses the dynamic values):
When the alert triggers, TradingView replaces {{strategy.order.alert_message}} with the complete JSON containing the calculated SL/TP values.
Last updated