Platform Documentation

Platform Overview

Connect by Trado is a webhook-powered trading automation platform that connects your TradingView alerts (or any webhook source) directly to your broker accounts. Execute trades automatically, manage multiple accounts, and scale your strategies — all without writing a single line of code.

Instant Execution

Sub-50ms webhook processing for real-time trade execution.

Enterprise Security

AES-256-GCM encryption for all API credentials.

9 Action Types

ENTRY, EXIT, PARTIAL_EXIT, FLIP, and more.

Copy Trading

Follow expert traders or share your strategies.

Supported Brokers

Currently, Connect by Trado supports CoinDCX (Futures & Spot trading). More brokers will be added in the future.

Getting Started

Follow these steps to start automating your trades:

1

Create an Account

Sign up with your email or Google account. Verify your email with a 6-digit OTP.

2

Add Your Broker Account

Open "Add broker" and enter your CoinDCX API credentials (API Key + API Secret). Your credentials are encrypted with AES-256-GCM.

3

Create a Webhook

Go to "Manage Webhooks" and create a new webhook. Select your broker and give it a descriptive name.

4

Deploy Your Account

Deploy your broker account to the webhook. Set a multiplier to scale your position sizes.

5

Configure Your Alert Source

Copy the webhook URL and paste it into TradingView (or any alert source). Set up the JSON payload.

6

Start Trading

Your alerts will now automatically execute trades on your deployed broker accounts!

API Management

Broker API accounts are the bridge between Connect by Trado and your exchange. You need to add at least one API account before you can deploy to a webhook.

Adding a Broker Account

Navigate to Dashboard → Add broker and enter your CoinDCX account credentials.

FieldRequiredDescription
Broker
Required
Select from supported brokers (CoinDCX)
Account Name
Required
A display name for your account (1–100 chars)
API Key
Required
Your broker API key (encrypted at rest with AES-256-GCM)
API Secret
Required
Your broker API secret (encrypted at rest with AES-256-GCM)

Account Features

• Credential Verification — Your API credentials are verified with the broker on creation. You can re-verify at any time.

• Balance Check — View real-time balances (available, locked, total) directly from your dashboard.

• Broker Info — Fetch your broker user profile and account details.

• Active/Inactive Toggle — Deactivated accounts skip all webhook orders. Useful for temporarily pausing execution.

• Visual ID — Each account gets a unique human-readable identifier (e.g., "A1B2C3").

Webhook Management

Webhooks are the core of the platform. Each webhook has a unique URL that accepts JSON payloads to execute trades on all deployed accounts.

Creating a Webhook

Navigate to Dashboard → Manage Webhooks and click "Create Webhook". Select a broker and provide a name and optional description.

Webhook URL

Each webhook gets a permanent URL that never changes:

POST https://connect.trado.trade/webhook/{webhook_url_id}

💡 Important: webhook_url_id vs access_code

The webhook_url_id (32 chars) is the permanent URL identifier — it never changes. The access_code (8 chars) is for sharing with subscribers and can be regenerated without affecting the URL.

Webhook Properties

PropertyDescription
is_activeToggle webhook on/off. Inactive webhooks reject all triggers.
is_publicPublished for subscription by other users.
is_invite_onlyOnly users whose TradoConnectID is in the invite list can subscribe.
welcome_messageMessage shown to subscribers when they join.
is_listedListed on the public marketplace for discovery.

Webhook Lifecycle

1. Create — Private webhook with unique URL

2. Deploy Accounts — Attach broker accounts with multiplier

3. Publish (optional) — Make public/invite-only with welcome message

4. List on Marketplace ( subject to review ) — Make discoverable on the marketplace. This requires admin approval to ensure quality control.

5. Share — Share access code for subscribers to join

Cooldown

The platform includes an in-memory cooldown service that filters identical payloads fired in rapid succession. The default cooldown window is 500ms — identical payloads within this window are automatically filtered.

The cooldown is a safety net, not a guarantee. It only catches repeats that arrive almost at the same time and are handled by the same server, and it forgets them once the window has passed. To make sure a request is carried out at most once, add an idempotency_key to the payload — see Idempotency.

Cooldown service can be turned off for any HFT strategy. This can be done by using the Cooldown Protection toggle in the Edit Webhook Modal.

Webhook Payload & Syntax

The webhook accepts JSON payloads. The platform supports three parser formats detected automatically.

Parser Detection (Priority Order)

1. CoinDCX Futures Parser — Detected via AT: "COINDCXFUTURE"

2. CoinDCX Spot Parser — Detected for CoinDCX spot format

3. Standard Parser — Fallback for payloads using the action field

Standard Payload Format

{
  "action": "ENTRY",
  "symbol": "B-BTC_USDT",
  "side": "BUY",
  "quantity": 0.001,
  "price": 0,
  "order_type": "market_order",
  "leverage": 10,
  "margin_mode": "ISOLATED",
  "take_profit_price": 105000,
  "stop_loss_price": 95000,
  "margin_currency_short_name": "USDT"
}

CoinDCX Futures Payload Format

{
  "AT": "COINDCXFUTURE",
  "ID": "ENTRY",
  "S": "B-BTC_USDT",
  "SD": "BUY",
  "Q": 0.001,
  "P": 0,
  "LVG": 10,
  "MT": "ISOLATED",
  "TP": 105000,
  "SL": 95000,
  "margin_currency_short_name": "USDT"
}

Complete Field Reference

FieldAliasesTypeDescription
atATstringWhere to perform (e.g., COINDCXFUTURES)
actionACTION, IDstringAction to perform (see Supported Actions)
symbolSYMBOL, S, PAIRstringTrading pair (e.g., B-BTC_USDT)
sideSIDE, SDstringBUY / SELL / B / S / LONG / SHORT
quantityQ, QTYnumberBase quantity (before multiplier)
priceP, PRICEnumberLimit price (0 or omit for market order)
leverageLVG, LEVERAGEnumberLeverage multiplier
order_typeORDER_TYPEstringmarket_order / limit_order
stepqtystep_qty, STEPQTYnumberQuantity rounding increment (auto-fetched if not provided)
price_stepSTEPnumberPrice rounding increment (auto-fetched if not provided)
percentPERCENTnumberExit percentage (1–100) for PARTIAL_EXIT
qty_typeQTY_TYPEstringDynamic sizing mode: CAPITAL_PCT, MARGIN_PCT, RISK_PCT, SIZE_AMOUNT, or MARGIN_AMOUNT. See Quantity Modes below. When set, quantity holds the percentage (for *_PCT) or the amount in the margin currency (for *_AMOUNT).
margin_basisMARGIN_BASISstringWhat a MARGIN_PCT percentage is taken of: AVAILABLE (default) or EQUITY (available balance + margin locked in open positions). Only valid with qty_type: MARGIN_PCT. See Margin basis below.
max_margin_pctMAX_MARGIN_PCTnumberCap on the margin a RISK_PCT entry may lock, as a percentage of equity (above 0, up to 100). Only valid with qty_type: RISK_PCT. See Margin cap below.
take_profit_priceTPnumberTake profit value (price, percentage, or points based on mode)
stop_loss_priceSLnumberStop loss value (price, percentage, or points based on mode)
sl_tp_modeSL_TP_MODEstringCombined SL/TP mode: PRICE (default) / PERCENTAGE / POINTS
sl_modeSL_MODEstringSL mode override: PRICE / PERCENTAGE / POINTS
tp_modeTP_MODEstringTP mode override: PRICE / PERCENTAGE / POINTS
TP_LEVELStp_levelsarrayMulti-target take-profit ladder (max 10 rungs). Each element is { percent, price }. ENTRY and the FLIP re-entry only — see Multi-Target Take Profit below.
TP_LIMITtp_limitbooleanDefault false. When true, every TP_LEVELS rung is placed as take_profit_limit instead of take_profit_market.
stop_price—numberStop/trigger price for stop orders
time_in_force—stringgood_till_cancel / fill_or_kill / immediate_or_cancel
reduce_onlyREDUCE_ONLYbooleanOnly reduce existing position
margin_modeMTstringISOLATED / I / CROSS / C — Only applies to ENTRY. Ignored for EXIT/CLOSE actions (uses position's existing mode).
margin_currency_short_namemargin_currencystringUSDT / INR — Defaults to INR if not provided
binance_symbolBINANCE_SYMBOLbooleanDefault false. When true, the symbol/pair is treated as Binance futures notation (e.g. NEWTUSDT.P) and automatically converted to CoinDCX format (e.g. B-NEWT_USDT).
complete_exit_before_flip—booleanDefault false. FLIP only — when true, the existing position is fully closed (via a complete position exit) before the new entry, ignoring the deployment multiplier for the exit leg.
idempotency_keyIDEMPOTENCY_KEYstringOptional. Makes the request execute at most once on this webhook: a repeat with the same key is answered duplicate and places nothing. 1–128 characters from A–Z a–z 0–9 . _ : -. See Idempotency.

Default Margin Currency

If margin_currency_short_name is not provided in the payload, the action will be executed on the INR margin by default. This applies to all actions including ENTRY, EXIT, PARTIAL_EXIT, CLOSE_SYMBOL, UPDATE_SLTP, CANCEL_ALL_ORDERS, and FLIP. Always specify margin_currency_short_name: "USDT" if you are trading on USDT margin pairs. The one exception is an ENTRY or FLIP with qty_type: RISK_PCT, which must state the margin currency: without it the payload is rejected.

Quantity Calculation

The final executed quantity is calculated as:

Final Quantity = roundUp(quantity × multiplier, stepqty)

// Dynamic sizing modes (set via qty_type):
CAPITAL_PCT: quantity = (available_balance × percent / 100) / pricePerContract
MARGIN_PCT:  quantity = (available_balance × percent / 100) / (1/leverage + fee) / pricePerContract
RISK_PCT:    quantity = (equity × percent / 100 / stopDistance) / pricePerContract
             equity = balance + locked margin (unrealised P&L excluded)
             stopDistance = |reference − stop| / reference
SIZE_AMOUNT:   quantity = amount / pricePerContract
MARGIN_AMOUNT: quantity = amount / (1/leverage + fee) / pricePerContract

// fee = taker fee (GST-inclusive for INR), so initial margin + entry fee
// equals the margin you asked for. Every size is capped to CoinDCX's
// position limit for the chosen leverage.

// MARGIN_PCT with margin_basis EQUITY (default AVAILABLE): the percentage is
// taken of equity (available + margin locked in open positions), never more
// than the available balance:
//   margin = min(equity × percent / 100, available_balance)

// RISK_PCT ignores the multiplier and rounds down to the lot step. With
// max_margin_pct the notional is also capped so that margin plus fee is at
// most equity × max_margin_pct / 100, before the available-balance clamp.

Quantity Modes (qty_type)

By default quantity is an absolute amount that the deployment multiplier is applied to. Set qty_type to size each account dynamically instead. The percentage modes use the account's own balance; the amount modes use a fixed value in the margin currency (INR/USDT).

qty_typequantity meansCalculation
CAPITAL_PCT% of available balance (1–100)notional = balance × pct / 100
MARGIN_PCT% of available balance as margin (1–100)notional = balance × pct / 100 ÷ (1/leverage + fee)
RISK_PCT% of account equity to lose if the stop is hit (above 0, up to 100, typically 0.5–5). Needs stop_loss_price on the same payload.notional = equity × pct / 100 / stopDistance, capped by max_margin_pct (if set) and by what the available balance can margin
SIZE_AMOUNTFixed position size in margin currencynotional = amount
MARGIN_AMOUNTFixed margin amount in margin currencynotional = amount ÷ (1/leverage + fee)

💡 Amount modes (SIZE_AMOUNT / MARGIN_AMOUNT)

For SIZE_AMOUNT and MARGIN_AMOUNT, quantity is the absolute amount in the margin currency (not a percentage). It follows whatever margin_currency_short_name you set (INR or USDT). For MARGIN_AMOUNT the entry fee is reserved out of the amount, so margin plus fee never exceeds what you entered; sizes are also capped to the leverage tier CoinDCX allows. leverage is required for MARGIN_AMOUNT.

Example — fixed ₹10,000 position size:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-BTC_USDT",
  "side": "BUY",
  "quantity": 10000,
  "qty_type": "SIZE_AMOUNT",
  "leverage": 10,
  "margin_currency_short_name": "INR"
}

Example — fixed ₹5,000 margin at 5×:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-ETH_USDT",
  "side": "SELL",
  "quantity": 5000,
  "qty_type": "MARGIN_AMOUNT",
  "leverage": 5,
  "margin_currency_short_name": "INR"
}

Margin basis (margin_basis, MARGIN_PCT only)

MARGIN_PCT takes its percentage of the account's available balance: the wallet minus the margin already locked in open positions. With several positions open, each later entry is therefore smaller than one sized from total equity. Set margin_basis to EQUITY to take the percentage of available balance + locked margin instead; the margin is still capped at the available balance, because only the free part can be margined. AVAILABLE is the default and is the same as leaving the field out. The value is case-insensitive; EQUITY with any other qty_type, or any other value, is rejected rather than ignored.

Example: ₹100,000 wallet, ₹40,000 locked in open positions (₹60,000 available), quantity 10. AVAILABLE gives a margin budget of ₹6,000; EQUITY gives ₹10,000.

Example — 10% of equity as margin at 10×:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-ETH_USDT",
  "side": "SELL",
  "quantity": 10,
  "qty_type": "MARGIN_PCT",
  "margin_basis": "EQUITY",
  "leverage": 10,
  "margin_currency_short_name": "INR"
}

Risk-based sizing (RISK_PCT)

For strategies that define size by risk per trade. quantity is the percentage of the futures wallet's equity to lose if the stop fills. Equity is the balance plus the margin locked in open positions; it excludes unrealised P&L. The eleventh position of a basket is therefore sized from the same base as the first. CAPITAL_PCT uses the available balance; MARGIN_PCT the available balance, or equity with margin_basis EQUITY.

The stop distance is measured against the limit price when one is set, otherwise the live price when the order is sized: PERCENTAGE stops give it directly, PRICE and POINTS stops are divided by the reference. An omitted sl_tp_mode means PRICE. Leverage does not change the size the risk calls for; it sets the margin that size locks, which is what max_margin_pct and the available balance cap. An ENTRY or FLIP with RISK_PCT needs both stop_loss_price and margin_currency_short_name (the INR default does not apply to this mode); without either it is answered HTTP 400 with the reason before anything is queued. See Response below.

The risk is approximate: fees, stop slippage and gaps can make the loss larger, and the stop must sit inside the liquidation distance at the chosen leverage. The quantity is rounded down to the lot step, so rounding never adds risk. Guard rails: a stop closer than 0.1% of the entry (or five times the fee rate) is refused; an account whose minimum order size would risk more than 1.5× the requested amount is refused with the numbers rather than oversized; a deployment with invert_signal is refused for RISK_PCT entries. The deployment multiplier is not applied. COINDCXFUTURE payloads only: a spot or standard payload naming RISK_PCT on an ENTRY or FLIP is rejected (exits are never refused). RISK_PCT is not available for copy groups, and Chase / Edit (replacing a linked order) cannot re-size by it: that request is answered 400 "RISK_PCT cannot re-size a linked order". A FLIP sizes its re-entry after the exit leg has closed: the wallet is read again, so equity then includes the closed position's realised P&L and fees. Each sized order records a sizing block with the order (equity, risk amount, stop distance, requested and placed notional, whether the available balance, max_margin_pct or the leverage tier decided the size, whether the minimum lot had to exceed the margin cap (min_lot_over_cap), and the risk the final quantity actually carries), kept with the order log. Example: ETH at 2000, equity ₹300,000, quantity: 2, stop 1940 (3% away) → risk ₹6,000, notional ₹200,000.

Example — risking 2% of equity with a stop 3% away:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "pair": "ETHUSDT",
  "binance_symbol": true,
  "side": "BUY",
  "qty": 2,
  "qty_type": "RISK_PCT",
  "leverage": 5,
  "margin_mode": "ISOLATED",
  "margin_currency_short_name": "INR",
  "stop_loss_price": 1940,
  "take_profit_price": 2180,
  "sl_tp_mode": "PRICE"
}

Margin cap (max_margin_pct, RISK_PCT only)

A tight stop makes a risk-based position large: risking 2% on a stop 1.1% away is a notional of about 1.8× equity. max_margin_pct caps the margin such a position may lock, as a percentage of equity, so several open positions cannot over-commit the wallet. The size is reduced until its margin plus entry fee is at most equity × max_margin_pct / 100, so the risk it then carries is smaller than requested. A basket that allows N open positions can use 100 ÷ N (16.66 for six). The cap is applied before the available-balance and leverage-tier limits, which can still reduce the size further.

The cap is a bound except for the exchange's minimum lot. If even one minimum lot needs more margin plus fee than the cap, a minimum lot whose margin plus fee is up to 1.5× the cap is still placed (the order's sizing block flags it as min_lot_over_cap); beyond 1.5× the cap the entry is refused, with both numbers in the reason.

max_margin_pct (alias MAX_MARGIN_PCT) is a number above 0 and at most 100, or a numeric string. It is read on ENTRY and FLIP only and ignored on every other action, so an exit is never refused over it. It is valid only with qty_type: RISK_PCT: with any other qty_type, or a value outside that range, the payload is rejected rather than ignored (answered HTTP 400; see Response below).

Example: equity 10,000, quantity 2 (risk 200), stop 1.1% away, 10× leverage. The risk calls for a notional of about 18,180, which needs about 1,829 of margin plus fee (at a 0.059% fee): 18.3% of equity. With max_margin_pct 16.66 the margin is held to 1,666, the notional to about 16,560, and the risk actually carried to about 182 (1.82% of equity).

Example — risking 2% of equity, margin capped at 16.66%:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "pair": "ETHUSDT",
  "binance_symbol": true,
  "side": "BUY",
  "qty": 2,
  "qty_type": "RISK_PCT",
  "max_margin_pct": 16.66,
  "leverage": 10,
  "margin_mode": "ISOLATED",
  "margin_currency_short_name": "INR",
  "stop_loss_price": 1978,
  "take_profit_price": 2044,
  "sl_tp_mode": "PRICE"
}

Entries are placed one at a time per account

Entries sized by RISK_PCT, or by MARGIN_PCT with margin_basis EQUITY, are placed one at a time per account and margin currency (each waits at most 15 s, then goes ahead anyway; other accounts are never delayed). Each entry is sized after the previous one has taken its margin, so a burst of signals on one account is sized against the free balance the account will really have. Other sizing modes, and every exit, are never held back.

Auto Instrument Specs

If stepqty or price_step is not provided in the payload, the platform try to automatically fetches instrument specifications from the broker/exchange to ensure proper rounding.

Where the Multiplier Applies

Every deployed account (and every copy-group member) carries its own multiplier. It scales absolute quantities only. Anything already expressed as a percentage of the account's own balance or its own live position is left untouched, because that value is per-account by definition and scaling it again would double-count the multiplier.

Action / modeMultiplierWhat each account gets
ENTRY / FLIP re-entry with absolute quantity
Applied
quantity × multiplier, rounded to the instrument step
qty_type: SIZE_AMOUNT / MARGIN_AMOUNT
Applied
The amount is a fixed figure shared by every account, so the resolved quantity is scaled
qty_type: CAPITAL_PCT / MARGIN_PCT / RISK_PCT
Not applied
Sized from each account's own balance (RISK_PCT: its own equity) — 10% means 10% on every account
PARTIAL_EXIT with percent
Not applied
percent of that account's live position — 50% closes half on every account
PARTIAL_EXIT with absolute quantity
Applied
quantity × multiplier, capped at the live position
EXIT with a quantity
Applied
quantity × multiplier, capped at the live position
CLOSE_SYMBOL / CLOSE_ALL
Not applied
The whole live position is closed, whatever its size
FLIP exit leg with complete_exit_before_flip: true
Not applied
Full position exit, so the account is guaranteed flat before the re-entry
TP_LEVELS rungs
Quantity only
Rung quantities follow the scaled order quantity; trigger prices are identical on every account
UPDATE_SLTP / CANCEL_ALL_ORDERS / SKIP
N/A
No quantity is involved

💡 Rule of thumb

A percentage is never multiplied. A quantity or a fixed amount always is. So a 50% partial exit closes half the position on a 1× account and half the position on a 3× account — the 3× account simply has a larger position to take half of.

Multi-Target Take Profit (TP_LEVELS)

CoinDCX Futures allows only one full-position take profit and one full-position stop loss per position — those are take_profit_price and stop_loss_price. To scale out at several targets, add TP_LEVELS. Each rung becomes its own take_profit_market (default) or take_profit_limit order sized to a percentage of the order quantity.

These order types are position-linked on CoinDCX, so they are cancelled automatically when the position closes or when its stop triggers. No stale target is left behind to re-open a reverse position. TP_LEVELS is honoured for ENTRY and for the re-entry leg of FLIP only — every other action ignores it.

FieldTypeRequiredDescription
TP_LEVELSarrayNoOrdered ladder — element 1 is TP1, element 2 is TP2, and so on. Maximum 10 rungs. Accepted as a JSON array or as a JSON string (handy for plain-text TradingView alerts).
TP_LEVELS[].percentnumberYesPercentage of the order quantity to close at this rung. All percentages must sum to 100 or less.
TP_LEVELS[].pricestring / numberYesTarget as an absolute price (1234), a percentage ("10%") or points ("10point").
TP_LIMITbooleanNotrue places every rung as take_profit_limit. Default false (take_profit_market).
time_in_forcestringNoApplies to take_profit_limit rungs only: good_till_cancel (default), immediate_or_cancel, fill_or_kill. Omitted for market rungs, as CoinDCX requires.

Price notation

price resolves against the same reference price used by take_profit_price / stop_loss_price — the limit price when one is set, otherwise the live market price — and always moves in the position's profit direction.

NotationBUY (long)SELL (short)
"1234"12341234
"10%"ref × 1.10ref × 0.90
"10point"ref + 10ref − 10

Example — 70% at +10 points, 30% at +10%:

{
  "AT": "COINDCXFUTURE",
  "ID": "ENTRY",
  "SYMBOL": "B-ETH_USDT",
  "SIDE": "BUY",
  "QTY": 700,
  "qty_type": "SIZE_AMOUNT",
  "LVG": 25,
  "margin_currency_short_name": "INR",
  "stop_loss_price": 10,
  "take_profit_price": 10,
  "sl_tp_mode": "PERCENTAGE",
  "TP_LEVELS": [
    { "percent": 70, "price": "10point" },
    { "percent": 30, "price": "10%" }
  ]
}

With a reference price of 2000 and SIZE_AMOUNT 700 resolving to a quantity of 800:

LegOrderQuantityTrigger
Entrymarket buy, full-position SL 1800 + TP 2200800—
TP1take_profit_market sell560 (70%)2010
TP2take_profit_market sell239 (30%, trimmed)2200

Behaviour notes

• Rung quantities always sum to less than the order quantity. One step size is reserved so the full-position TP/SL keeps a residual to close — that is why TP2 above is 239 and not 240.

• Multipliers scale quantity only. A 3× deployment gets rungs of 1680 / 719 at the same trigger prices, because prices come from the reference price, not from quantity.

• Prices and quantities are rounded to the instrument's price_increment and quantity_increment. A rung that rounds below min_quantity is skipped and logged instead of being rejected by the broker.

• Limit rungs get a trigger offset. For take_profit_market the price you give is the trigger. For take_profit_limit your price is the limit and the trigger sits 0.5% beyond it, to satisfy CoinDCX's ordering rules.

• Rungs are placed one second after the entry. The entry has to register as an open position first, otherwise CoinDCX books the targets as fresh risk and locks extra margin. Triggers are processed asynchronously, so this costs no webhook latency.

• A malformed ladder rejects the webhook before any order is placed, so a position is never opened without the targets you asked for.

• Rungs never fail the entry. Once the entry is accepted, a rung the broker rejects is recorded on its own TP_LEVEL order log and the entry still reports SUCCESS. Each rung appears as its own order log with type TP_LEVEL.

Binance Symbol Conversion

If your alert source sends symbols in Binance futures notation, set binance_symbol: true and the platform converts the symbol to CoinDCX format automatically before execution.

Binance notationConverted (CoinDCX)
NEWTUSDT.PB-NEWT_USDT
RAREUSDT.PB-RARE_USDT
ETHUSDC.PB-ETH_USDC
{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "NEWTUSDT.P",
  "side": "BUY",
  "quantity": 100,
  "binance_symbol": true,
  "margin_currency_short_name": "USDT"
}

Idempotency (Never Place an Order Twice)

Requests get repeated: a call times out and you cannot tell whether Connect received it, an alert fires twice, a script retries. Add an idempotency_key to the payload and Connect carries that key out at most once on the webhook. Every later request with the same key is answered 202 with "status": "duplicate", and nothing is placed.

{
  "action": "ENTRY",
  "symbol": "B-ETH_USDT",
  "side": "BUY",
  "quantity": 0.012,
  "margin_currency_short_name": "USDT",
  "idempotency_key": "strategy-7.2026-10-16T09:00:00Z.entry"
}

The rules

• Field. idempotency_key; the name is not case-sensitive, so IDEMPOTENCY_KEY works too. It is read in all three payload formats and on every action: ENTRY, EXIT, PARTIAL_EXIT, CLOSE_SYMBOL, CLOSE_ALL, UPDATE_SLTP, CANCEL_ALL, FLIP and SKIP. Other fields such as signal_id are not read as a key. There is no Idempotency-Key header, because TradingView cannot set headers.

• Value. Text of 1 to 128 characters from A–Z a–z 0–9 . _ : -; spaces around it are trimmed. A whole number below 9,007,199,254,740,992 is also accepted and treated as text. Anything else (empty, longer than 128 characters, other characters, true/false, an object) makes the payload invalid, and it is answered like any other invalid payload (see Response). With the idempotency switch off, an invalid key is ignored, not rejected: the request is handled as if it had no key.

• Scope. One webhook. The same key sent to another webhook is a different request.

• One key, one payload. Connect stores a fingerprint of what the request does: the action, symbol, side, size and sizing mode, price, percent, leverage, margin settings (mode and currency), order type, stops and take-profit targets. The key itself, the raw payload, labels, comments and timestamps are not part of it, so a retry that differs only in such noise is a plain repeat. Sending the key again with a different fingerprint (another symbol, side or quantity, say) is a mistake in the key, and is answered 422 with IDEMPOTENCY_KEY_PAYLOAD_MISMATCH. Nothing is placed, and nothing is passed on to a group's members.

• Window. A used key stays a duplicate for 48 hours after the request that executed it. After that, the same key is treated as new.

• At most once. The first request with a key executes. Any later request with the same key is a duplicate, even while the first is still being processed, and even if the first failed or was refused on every account. To try again, send a new key.

• One exception: nothing reached the broker. If Connect can show that the first request never got as far as the broker (trading was halted, the payload could not be processed, the webhook was deactivated or could not be read just after the request arrived), the key is released and a resend with the same key executes. The Read-back API tells you which case you are in (same_key_retry).

• No record for an inactive or unknown webhook. A request to a webhook that is inactive or unknown when it arrives is answered 202 and places nothing. Its key is not recorded, so a later request with the same key is not a duplicate, and the Read-back API has no entry for it.

• Checked before the cooldown. A rapid repeat with the same key is a duplicate, not a cooldown skip.

• In the logs. Each repeated request is recorded as one log row with status DUPLICATE. It executed nothing and is not counted in the trigger totals. The row names the request that owns the key. On a group member's webhook it can also carry duplicate_payload_mismatch: true: the member saw a repeat whose payload differs from the original's.

Which key to send

Your situationSend
You do not know whether the first attempt arrived (timeout, 5xx, connection reset)The same key. If the first attempt arrived, you get duplicate; if it did not, this one executes.
A deliberate second attempt, after the read-back shows the first was refused or failedA new key.
A new signal or a different orderA new key.

TradingView

Build the key from {{strategy.order.id}} and {{timenow}}, for example "idempotency_key": "{{strategy.order.id}}-{{timenow}}". Each alert gets its own key, and a re-delivery of the same alert shares it. Without {{timenow}}, two different alerts can share a key, and the second is answered 422 or duplicate and never placed. Keep order ids to the characters listed above: a space makes the payload invalid.

What happens when

CaseResult
Two identical requests arrive at the same momentOne executes. The other is a duplicate.
A repeat arrives while the original is still being processedDuplicate. It is never placed twice.
The original failed, or was refused on every accountDuplicate: the key is used. Send a new key to try again.
The original never reached the broker (trading halted, payload could not be processed, webhook deactivated just after the request arrived)The key is released. A resend with the same key executes.
The webhook is inactive or unknown when the request arrivesAnswered 202 with nothing placed and nothing recorded. The key is not used, and the read-back has no entry for it.
The key is sent again with a different payloadAnswered 422 IDEMPOTENCY_KEY_PAYLOAD_MISMATCH. Nothing is placed. Send a new key for a new order.
Connect stopped after accepting the request but before sending anything to the brokerThe key is freed after 2 to 3 minutes. A resend then executes.
Connect stopped after orders had started going outThe key stays used. Check the read-back for the outcome.
Connect could not record the keyThe request is answered 503 and nothing is executed. Retry with the same key. If the key had in fact been saved, a retry may answer duplicate for up to 3 minutes. Nothing is placed twice.
A group member's key cannot be recordedThat member executes nothing, and its webhook log is FAILED with the reason CLAIM_ERROR. Resend with the same key.
The key is older than 48 hoursIt is treated as new, and the request executes.
The idempotency switch is off (the response says "idempotency": "disabled")A valid key is stored on the log but not enforced, and the read-back has no entry for it. An invalid key is ignored, not rejected. Do not rely on the key to prevent repeats.

Response

A POST to the webhook URL is answered 202 Accepted once the payload is received; the orders are placed afterwards, in the background. The 202 means "received", not "every account was filled": each account's outcome (see Execution Results under Manual Trading Actions) is in the webhook log, and for a request that carried an idempotency key also in the Read-back API. A repeated key is also answered 202, so callers that only look at the status code keep working. TradingView ignores the body.

Example — accepted:

{
  "success": true,
  "status": "accepted",
  "message": "Webhook trigger accepted for processing",
  "request_id": "9b0d3f3e-5d0a-4a57-9a43-2f1f7c1a6b10",
  "client_request_id": "01K7A1Q2.01K7A1Q3.entry.0:1",
  "idempotency_key": "01K7A1Q2.01K7A1Q3.entry.0",
  "idempotency": "enforced"
}
FieldPresentMeaning
statusEvery answer except a 400accepted, duplicate (see below), unavailable (a 503) or error (a 422).
request_idAlwaysConnect's id for this request. It is unique per request, and shown as Request ID in the logs.
client_request_idWhen you sent a valid X-Request-IdYour own id, echoed back.
idempotency_keyWhen the payload carried a keyThe key, as Connect read it.
idempotencyWhen the payload carried a keyenforced, or disabled when the platform is not enforcing keys. In that case do not retry an ENTRY: a repeat would execute again.

Example — duplicate (also 202; nothing was placed again):

{
  "success": true,
  "status": "duplicate",
  "message": "Duplicate idempotency_key: this webhook already received it; nothing was placed again",
  "request_id": "5c1e8a47-92b0-4d3f-a6c5-1e7f0b2d9a38",
  "client_request_id": "01K7A1Q2.01K7A1Q3.entry.0:2",
  "idempotency_key": "01K7A1Q2.01K7A1Q3.entry.0",
  "idempotency": "enforced",
  "original_request_id": "9b0d3f3e-5d0a-4a57-9a43-2f1f7c1a6b10",
  "original_received_at": "2026-10-16T09:00:01.123456Z",
  "original_committed": true
}
FieldMeaning
original_request_id, original_received_atThe request that owns the key, and when it arrived.
original_committedtrue: the original has started executing or has executed. false: it has not started yet. It can still be released without executing (for example because trading is halted), and then this repeat has placed nothing either. When it is false, confirm the original in the Read-back API: same_key_retry: "execute" means the key is free, so send the same key again.

The answer is duplicate whether the original is still being processed or has finished. The original's outcome is in the Read-back API.

Example — the key could not be recorded (503, with a Retry-After: 1 header). Only requests that carry a key can get this:

{
  "success": false,
  "status": "unavailable",
  "error": "The idempotency key could not be recorded, so nothing was executed. Retry with the same key.",
  "request_id": "2f6b0c9d-4a1e-47d8-b3a5-8e9c7d1f4a62",
  "idempotency_key": "01K7A1Q2.01K7A1Q3.entry.0"
}

Example — the key was already used with a different payload (422; nothing was placed):

{
  "success": false,
  "status": "error",
  "error": "IDEMPOTENCY_KEY_PAYLOAD_MISMATCH",
  "message": "This idempotency_key was already used for a different request on this webhook, so nothing was placed. Use a new key for a new request.",
  "request_id": "4a7d9e12-6c3b-4f58-a0e1-3b8c5d2f9a71",
  "client_request_id": "01K7A1Q2.01K7A1Q3.entry.1:1",
  "idempotency_key": "01K7A1Q2.01K7A1Q3.entry.0",
  "original_request_id": "9b0d3f3e-5d0a-4a57-9a43-2f1f7c1a6b10"
}
FieldMeaning
error, messageerror is the code to test for; message is a sentence for people and may be reworded.
original_request_idThe request id of the request that first used the key.

Request ids

• request_id is minted by Connect for every request and is never reused.

• X-Request-Id is an optional header you can add to tag a request with your own id (1–128 characters from A–Z a–z 0–9 . _ : -). Connect echoes it as client_request_id, stores it on the log row, and shows it in the logs. A value in another format is ignored, not rejected. It does not need to be unique: retries can reuse it. Putting the attempt number in it, such as my-signal-42:2, tells attempts apart.

• The X-Request-ID response header is for Connect's own access logs and is a different value. Use the request_id in the body.

Other answers

• Invalid payload. A payload that is valid JSON but that Connect cannot parse — for example RISK_PCT without stop_loss_price, max_margin_pct with another qty_type, an unknown margin_basis, or an invalid idempotency_key (while the idempotency switch is off an invalid key is ignored instead) — is answered 400 Bad Request with the reason, before anything is queued. This is on by default; if the operator turns it off, such a payload is answered 202 and rejected in the background, and the reason appears only in Connect's server logs. A body that is not valid JSON is answered 400 either way. Every 400 body carries request_id (and client_request_id when you sent a valid header).

• Unknown or inactive webhook. Still 202, with the same body as a first accepted request, so a URL cannot be probed to find out which webhooks exist. A request with a key to such a webhook records nothing. Reading is different: the Read-back API answers 404 for an unknown URL.

Example — body of a 400 response (a RISK_PCT entry without a stop):

{
  "success": false,
  "error": "Invalid payload",
  "details": "missing required field: stop_loss_price is required for RISK_PCT sizing",
  "request_id": "7d2a5c1e-3b4f-4e0a-8f6d-2c9b1a7e5d30"
}

Supported Actions (9 Types)

ENTRY
Open New Position

Aliases: PLACE_ORDER, BUY, SELL, LONG, SHORT, OPEN

Required: symbol, side, quantity

Opens a new position or adds to an existing one. Supports market and limit orders, leverage setting, take-profit/stop-loss (with price, percentage, or points mode), and margin mode configuration.

Price-based SL/TP (default):

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-BTC_USDT",
  "side": "BUY",
  "quantity": 0.001,
  "leverage": 10,
  "margin_mode": "CROSS",
  "take_profit_price": 105000,
  "stop_loss_price": 95000,
  "margin_currency_short_name": "INR"
}

Percentage-based SL/TP:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-BTC_USDT",
  "side": "BUY",
  "quantity": 0.001,
  "leverage": 10,
  "stop_loss_price": 2,
  "take_profit_price": 5,
  "sl_tp_mode": "PERCENTAGE",
  "margin_currency_short_name": "INR"
}

SL = 2% below entry, TP = 5% above entry (inverted for SELL)

Points-based SL/TP:

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-BTC_USDT",
  "side": "BUY",
  "quantity": 0.001,
  "leverage": 10,
  "stop_loss_price": 500,
  "take_profit_price": 1000,
  "sl_tp_mode": "POINTS",
  "margin_currency_short_name": "INR"
}

SL = 500 points below entry, TP = 1000 points above entry (inverted for SELL)

💡 SL/TP Mode Priority

Use sl_tp_mode to set both SL and TP to the same mode. Use sl_mode / tp_mode individually to override. Individual modes take precedence over the combined mode. For EXIT actions, margin_mode is ignored — the position's existing margin type is used.

Multiple take-profit targets (TP_LEVELS):

{
  "AT": "COINDCXFUTURE",
  "action": "ENTRY",
  "symbol": "B-ETH_USDT",
  "side": "BUY",
  "quantity": 800,
  "leverage": 25,
  "stop_loss_price": 10,
  "take_profit_price": 10,
  "sl_tp_mode": "PERCENTAGE",
  "TP_LEVELS": [
    { "percent": 70, "price": "10point" },
    { "percent": 30, "price": "10%" }
  ],
  "margin_currency_short_name": "INR"
}

Scales out at two targets alongside the full-position SL/TP. See Multi-Target Take Profit under Payload & Syntax for the full rules.

EXIT
Close Entire Position

Required: symbol, side

Closes the full position for a given symbol. The side is auto-detected from the current position. Sets reduce_only: true automatically.

{
  "AT": "COINDCXFUTURE", 
  "action": "EXIT",
  "symbol": "B-BTC_USDT",
  "side": "SELL",
  "quantity": 0.001,
  "leverage": 10,
  "stepqty": 0.001,
  "step": 0.1,
  "margin_currency_short_name": "INR"
}

PARTIAL_EXIT
Close Percentage of Position

Aliases: PARTIAL, PARTIAL_CLOSE

Required: symbol, percent (1–100)

Optional: margin_currency_short_name — defaults to INR if not provided

Closes a specified percentage of the current position. Useful for scaling out of positions gradually.

The percentage is measured against each account's own live position and the deployment multiplier is not applied to it. A percent of 50 closes half the position on every account, whatever its multiplier. Send an absolute quantity instead if you do want the multiplier applied.

{
  "AT": "COINDCXFUTURE", 
  "action": "PARTIAL_EXIT",
  "symbol": "B-BTC_USDT",
  "percent": 50,
  "margin_currency_short_name": "USDT"
}

FLIP
Reverse Position Direction

Aliases: REVERSE, SWITCH

Required: symbol, side, quantity

Optional: margin_currency_short_name — defaults to INR if not provided. If no margin is specified, the exit leg automatically uses the position's margin currency.

Optional: complete_exit_before_flip (boolean, default false)

Closes the existing position and opens a new one in the opposite direction. Executed as two operations: close existing + open new.

{
  "AT": "COINDCXFUTURE", 
  "action": "FLIP",
  "symbol": "B-BTC_USDT",
  "side": "SELL",
  "quantity": 0.001,
  "leverage": 10,
  "margin_currency_short_name": "USDT"
}

💡 complete_exit_before_flip

By default the exit leg places a multiplier-scaled reduce-only order. Set complete_exit_before_flip: true to fully close the entire open position (regardless of multiplier) before opening the new entry — guaranteeing a flat position first.

{
  "AT": "COINDCXFUTURE",
  "action": "FLIP",
  "symbol": "B-BTC_USDT",
  "side": "SELL",
  "quantity": 0.001,
  "leverage": 10,
  "complete_exit_before_flip": true,
  "margin_currency_short_name": "USDT"
}

CLOSE_SYMBOL
Close All Positions for Symbol

Aliases: CLOSE_POSITION, CLOSE, EXIT_POSITION, EXIT_SYMBOL, EXIT_ALL_POSITION

Required: symbol

Optional: margin_currency_short_name — defaults to INR if not provided

Closes the full open position for a specific trading pair. Only AT, symbol, and margin_currency_short_name are used — all other parameters are ignored.

{
  "AT": "COINDCXFUTURE", 
  "action": "CLOSE_SYMBOL",
  "symbol": "B-BTC_USDT",
  "margin_currency_short_name": "USDT"
}

CLOSE_ALL
Close ALL Positions

Aliases: EXIT_ALL, CLOSE_ALL_POSITIONS, CLOSEALL

Emergency action that closes every open position on all deployed accounts. No symbol parameters required.

Optional: margin_currency_short_name — defaults to INR if not provided. Specify to target positions on a specific margin.

{
  "AT": "COINDCXFUTURE", 
  "action": "CLOSE_ALL",
  "margin_currency_short_name": "USDT"
}

CANCEL_ALL_ORDERS
Cancel All Pending Orders

Aliases: CANCEL, CANCEL_ALL

Cancels all pending/open orders on all deployed accounts.

Optional: margin_currency_short_name — defaults to INR if not provided.

{
  "AT": "COINDCXFUTURE",                  
  "action": "CANCEL_ALL_ORDERS",
  "margin_currency_short_name": "USDT"
}

UPDATE_SLTP
Update Stop-Loss / Take-Profit

Aliases: SLTP, SET_SLTP

Required: symbol, at least one of SL or TP

Optional: margin_currency_short_name, SLTPMODE

Updates the stop-loss and/or take-profit prices for an existing position. The broker is determined from the webhook — no AT field required. Supports price, percentage, and points modes via SLTPMODE.

Price mode (default):

{
  "action": "UPDATE_SLTP",
  "symbol": "B-BTC_USDT",
  "TP": 105000,
  "SL": 95000,
  "margin_currency_short_name": "USDT"
}

Percentage mode:

{
  "action": "UPDATE_SLTP",
  "symbol": "B-BTC_USDT",
  "SL": 3,
  "TP": 5,
  "SLTPMODE": "PERCENTAGE",
  "margin_currency_short_name": "USDT"
}

SL = 3% from entry price, TP = 5% from entry price (direction based on position side)

Points mode:

{
  "action": "UPDATE_SLTP",
  "symbol": "B-BTC_USDT",
  "SL": 500,
  "TP": 1000,
  "SLTPMODE": "POINTS",
  "margin_currency_short_name": "USDT"
}

SL = 500 points from entry, TP = 1000 points from entry (direction based on position side)

SKIP
No Operation

Aliases: NOP, NOOP, IGNORE, NO_OP

Does nothing. Useful for conditional logic in your alert scripts where certain conditions should skip execution.

{
  "AT": "COINDCXFUTURE",                  
  "action": "SKIP"
}

Read-back API

The 202 you get when you send a request only says "received". The read-back API tells you what happened afterwards. For every request that carried an idempotency_key it reports whether the request ran, on which of your accounts and with what outcome, and it lists the positions your accounts hold right now. Use it to confirm that a signal landed, to decide whether a resend is safe, and to reconcile after a timeout.

MethodPathReturns
GET/webhook/{webhook_url_id}/executionsOne entry per idempotency key sent to the webhook in the last 24 hours, with the outcome on each of your accounts.
GET/webhook/{webhook_url_id}/positionsThe open positions of your accounts that are deployed on the webhook.

Base URL https://connect.trado.trade. Both paths also work under /api/webhook/....

Access: the webhook URL id is the credential

As when sending, there is no header and no signature: the URL id itself is the secret. Anyone who has the URL can already trade on the webhook, so reading adds no new exposure. Keep the id out of chat messages and logs (in a shell, keep it in an environment variable). It is never repeated in a response body, and every answer carries Cache-Control: no-store.

curl "https://connect.trado.trade/webhook/$WEBHOOK_URL_ID/executions?since=2026-10-16T09:00:00Z"

Executions

Only requests that carried an idempotency_key are listed, in order of arrival. Each entry describes the request that owns the key; repeats of the key are counted in duplicates.

A key has an entry only if Connect recorded it. A key sent to a webhook that was inactive or unknown when the request arrived gets no entry, and neither does a key sent while the idempotency switch was off. A missing entry therefore does not tell you whether the request ran.

ParameterMeaning
sinceStart of the first page, as an RFC 3339 time. The default, and the earliest allowed, is 24 hours ago: an older value is moved up, and the answer's since shows the value used. A time in the future or in another format is answered 400 invalid_since.
cursorThe next_cursor of the previous page. It replaces since. Treat it as opaque; an invalid one is answered 400 invalid_cursor.
limitKeys per page: 100 by default, 1 to 500. A page can hold fewer keys than that (see truncated), so keep following next_cursor until it is null.

Example answer:

{
  "as_of": "2026-10-16T09:05:00.512Z",
  "since": "2026-10-16T09:00:00Z",
  "executions": [
    {
      "idempotency_key": "01K7A1Q2.01K7A1Q3.entry.0",
      "request_id": "9b0d3f3e-5d0a-4a57-9a43-2f1f7c1a6b10",
      "client_request_id": "01K7A1Q2.01K7A1Q3.entry.0:1",
      "action": "ENTRY",
      "symbol": "B-ETH_USDT",
      "received_at": "2026-10-16T09:00:01.123Z",
      "completed_at": "2026-10-16T09:00:03.020Z",
      "status": "filled",
      "reason_code": null,
      "same_key_retry": "duplicate",
      "duplicates": {
        "count": 1,
        "last_at": "2026-10-16T09:00:06.400Z",
        "last_request_id": "5c1e8a47-92b0-4d3f-a6c5-1e7f0b2d9a38"
      },
      "accounts": [
        {
          "deployment_ref": "3c1f6a2e-7b0d-4b8e-9d55-0f2a8c1e4d77",
          "status": "filled",
          "side": "BUY",
          "requested_qty": 0.012,
          "filled_qty": 0.012,
          "avg_price": 2451.37,
          "fill_source": "order_response",
          "reason_code": null,
          "reason": null,
          "exchange_code": null,
          "warning_code": null,
          "legs": 1,
          "executed_at": "2026-10-16T09:00:02.871Z"
        }
      ],
      "accounts_truncated": false,
      "other_accounts": {
        "count": 0, "filled": 0, "partial": 0,
        "refused": 0, "error": 0, "pending": 0
      }
    }
  ],
  "truncated": false,
  "next_cursor": null
}
FieldMeaning
as_of, sinceWhen the answer was produced, and the start time it used (see the since parameter).
truncated, next_cursornext_cursor is null on the last page; otherwise pass it as cursor to get the next page. truncated is true only when the page ended early because it reached the cap of 2,000 account rows; next_cursor then continues from the first key left out. A page cut only by limit has a next_cursor and is not truncated.
request_id, client_request_idConnect's id of the request that owns the key, and its X-Request-Id if it had one.
received_at, completed_atWhen Connect received the request and when it finished processing it. completed_at is null while the status is pending.
status, reason_codeThe outcome of the whole request, and why it was refused or failed. See the tables below.
same_key_retryexecute: the key was released because nothing reached the broker, so sending the same key again executes. duplicate: the key is used, so a retry needs a new key.
duplicatesHow many later requests were answered duplicate for this key, and the last one.
accountsThe outcome on each of your own accounts, up to 100 per key (accounts_truncated says if there were more).
other_accountsAccounts of other users deployed on a marketplace webhook, counted by status. They are never listed.

One account entry

FieldMeaning
deployment_refA random id for that account's deployment on this webhook. It stays the same for the life of the deployment. It is the only way an account is identified.
statusfilled, partial, refused, error or pending; see Statuses. An account that placed several orders (a FLIP exits and then enters) shows one status for all of them, by the rules in that table.
requested_qty, filled_qty, avg_priceThe quantity asked for, and what is known of the fill. filled_qty and avg_price are null when the fill is not known.
fill_sourceexchange_sync: executed quantity and average price taken from the exchange. order_response: taken from the exchange's answer when the order was created. null: not known yet.
reason_code, reason, exchange_codeWhy an order was refused or failed: a code from the table below and a fixed sentence (SKIPPED_UNKNOWN is the one exception). On a partial account they carry the reason of the order that was refused or failed. For EXCHANGE_REJECTED, exchange_code is the exchange's own error code when it is a plain code. The exchange's message text is never returned.
warning_codeTP_INCOMPLETE: the entry went through but a take-profit level could not be placed. The status is not downgraded for it.
legsHow many orders this request placed on the account.

filled means accepted by the exchange

A market order can still be settling when you read it, so filled_qty may be null, or lower than requested_qty (the account then reads partial), for a moment. The true quantities are the positions below. When you check for drift, compare positions, not filled_qty.

Statuses

StatusOn one accountOn the whole request
pending
An order of the account is still being processed.Not finished (completed_at is null): the key is reserved but execution has not completed, or the request is done but its per-account results are not written yet. Read again. A request whose results are still missing 2 to 3 minutes after it finished becomes error with INTERNAL, and so does one still pending 15 minutes after it arrived.
filled
Every order of the account filled in full.Every account filled in full.
partial
Something executed, but not everything in full: at least one order filled (fully or short of the requested quantity) and at least one did not fill in full (it was refused, it failed with an error, or its fill is short). A FLIP whose exit filled and whose entry was refused has closed the old position and not opened the new one. Check positions.At least one account filled or partial, and not every account filled in full.
refused
Nothing was executed for the account: every order was refused. reason_code says why.Nothing was executed: every account was refused, no account is deployed (NO_DEPLOYMENTS), or the key was released before execution (the reason code is then the release reason; see below).
error
Nothing filled and at least one order failed with an error: the exchange did not answer in time, or something failed inside Connect. An order may be live, so check positions before you resend.No account filled or partly executed and at least one failed with an error, or the request failed inside Connect.

Other users' accounts on a marketplace webhook are counted in other_accounts and also count in the request status.

Reason codeStatusMeaning
COOLDOWNrefusedAn identical payload arrived inside the cooldown window.
ACCOUNT_INACTIVErefusedThe account is not active.
OUTSIDE_TRADING_HOURSrefusedOutside the trading hours set for the account.
NO_POSITIONrefusedThere was no position to close or reduce.
HALTEDrefusedTrading was halted platform-wide. The order's message in the webhook log starts with Halted: followed by the operator's reason.
SKIPPED_UNKNOWNrefusedNothing was placed: Connect skipped the account for a reason it does not recognise. reason carries the order's own text (control characters removed, cut to 200 characters) instead of a fixed sentence. It is returned for your own accounts only.
BELOW_MIN_SIZErefusedThe size was below the exchange's minimum or lot step.
INSUFFICIENT_MARGINrefusedNot enough margin or balance.
SIZING_REFUSEDrefusedThe sizing rules refused the order (for example the RISK_PCT checks).
EXCHANGE_REJECTEDrefusedThe exchange rejected the order.
CREDENTIALSrefusedThe exchange rejected the account's API key, or Connect could not decrypt it.
BROKER_TIMEOUTerrorThe exchange did not answer in time. The order may be live: check positions before you resend.
INTERNALerrorSomething failed inside Connect, or the request never finished (see pending above).
NO_DEPLOYMENTSrefusedRequest level only: no account is deployed on the webhook.

The Status column is the account's status when none of its orders filled. Beside a filled order the account is partial and keeps the code of the order that did not fill.

A request whose key was released shows refused with same_key_retry: "execute" and one of these reasons: PARSE_ERROR, WEBHOOK_INACTIVE (the webhook was deactivated after the request arrived), WEBHOOK_UNAVAILABLE (the webhook could not be read after the key was recorded), BROKER_UNAVAILABLE, LOG_WRITE_FAILED, HALTED, DEPLOYMENTS_UNAVAILABLE, COMMIT_FAILED, CLAIM_ERROR (a group member's key could not be recorded: that member's webhook log is FAILED with this reason) or ORPHANED. Nothing reached the broker in any of them.

Positions

The current positions of your active accounts that are deployed on the webhook, read from the exchange and summed per symbol, side and margin currency. They are the accounts' real positions, whatever opened them: an account deployed on two webhooks reports the same positions on both.

{
  "as_of": "2026-10-16T09:05:00.512Z",
  "cached": false,
  "supported": true,
  "accounts": { "total": 3, "read": 2, "unreadable": 1, "truncated": false },
  "other_accounts": 12,
  "positions": [
    {
      "symbol": "B-ETH_USDT",
      "binance_symbol": "ETHUSDT",
      "side": "LONG",
      "margin_currency": "INR",
      "accounts": 2,
      "total_qty": 0.024,
      "avg_entry_price": 2451.37
    }
  ],
  "errors": [ { "code": "BROKER_TIMEOUT", "accounts": 1 } ]
}
FieldMeaning
cachedtrue when the answer comes from a short cache (about 4 seconds). Asking faster returns the same data.
supportedfalse when the webhook's broker has no futures positions; positions is then empty.
accountsHow many of your accounts exist on the webhook (total), how many were read, how many could not be read (unreadable) and whether the list was cut at 100 (truncated). An account with no open position counts as read.
other_accountsThe number of other users' accounts deployed on the webhook. They are never read.
positionsOne entry per symbol, side (LONG or SHORT) and margin currency: how many accounts hold it, total_qty (the sum of quantities) and avg_entry_price (weighted by quantity). binance_symbol is given for USDT pairs.
errorsAccounts that could not be read, counted by code: CREDENTIALS, BROKER_TIMEOUT or EXCHANGE_ERROR. Only codes with at least one account are listed; the list is empty when every account was read.

If accounts.unreadable is above zero, the totals do not cover every account. Do not treat them as complete.

Errors, and why an unknown URL is 404 here but 202 when sending

StatusMeaning
200The answer. Also for an inactive webhook, whose earlier keys and open positions can still be read.
400invalid_since or invalid_cursor, in the form {"error": "invalid_since"}.
404{"error": "not_found"}: no webhook has this URL id.
429Too many requests. The Retry-After header says how long to wait.
500{"error": "internal_error"}: reading failed inside Connect. The body has no other detail. Try again after a moment.
503{"error": "readback_disabled"}: reading is switched off.

Sending to an unknown URL is answered 202, so that a URL cannot be probed and sending stays fast. Reading has to look the webhook up anyway, and an empty 200 for a mistyped URL would read as "nothing executed" and hide the mistake from your reconciliation, so it answers 404.

Privacy

Only the accounts of the webhook's owner are reported. Other users who deployed accounts on a marketplace webhook appear only as counts in executions, and not at all in positions, because positions include trades from outside the strategy. Account ids, names, client ids, exchange user ids and keys are never returned; an account is identified by its deployment_ref only.

Limits and polling

• Rate limits. Executions: 60 requests a minute per webhook. Positions: 30 a minute per webhook. 1,200 a minute per IP address across both. Beyond that you get 429 with Retry-After.

• Size. At most 500 keys and 2,000 account entries per page, 100 of your accounts per key, a 24-hour window. Positions read at most 100 accounts.

• Polling. Ask no more often than every 5 seconds, and only while a key you care about is still pending. Start from the time you sent the oldest unsettled request, minus a minute, as since, and follow next_cursor. Stop polling once every key is final.

Account Deployment

Deploying an account to a webhook connects your broker account to receive and execute trade signals from that webhook.

Deployment Settings

SettingDefaultDescription
multiplier1.0Scales the base quantity. E.g., multiplier of 2 doubles the position size. Range: 0.01–100. It applies to absolute quantities and fixed-amount sizing only — not to percentage entries (CAPITAL_PCT / MARGIN_PCT) or percentage partial exits. See Where the Multiplier Applies under Payload & Syntax.
is_activetrueToggle deployment on/off without removing it.

Deployment Notifications

You receive email notifications for every deployment-related action:

Deploy

Account deployed to webhook

Undeploy

Account removed from webhook

Activate

Deployment activated

Deactivate

Deployment deactivated

Multiplier Change

Multiplier updated (shows old → new value)

Notification emails include: webhook name, exchange, account name, client ID, multiplier, status, access type (Private/Public/Listed), who performed the action (Owner/Subscriber), and timestamp.

Access Control

• Webhook Owner — Can see ALL deployments and perform actions on all accounts

• Subscriber — Can only see and manage their OWN deployments

Manual Trading Actions

In addition to webhook-triggered trades, you can execute trades manually from the dashboard. These actions are available on both webhooks and copy groups.

ActionParametersDescription
Place Order
Account(s), Symbol, Side, Quantity, Order Type, Price, TP/SLOpen a new position with full control over parameters
Partial Exit
Account(s), Symbol, Exit % or QuantityClose a percentage of an existing position
Exit All
Account(s)Close ALL open positions on selected accounts
Exit by Symbol
Account(s), SymbolClose all positions for a specific trading pair
Cancel All Orders
Account(s)Cancel all pending/open orders
Update SL/TP
Account(s), Symbol, TP Price, SL PriceSet or update stop-loss and take-profit prices

💡 Multiplier Application

The deployment multiplier scales the quantity for Place Order actions. It is not applied to a Partial Exit percentage — 50% closes half of each account's own position, whatever its multiplier — nor to Exit All / Close Symbol, which close the whole live position. A Partial Exit entered as an absolute quantity is still scaled, then capped at the live position. Full breakdown in Where the Multiplier Applies under Payload & Syntax.

Execution Results

Per account

SUCCESS
FAILED
SKIPPED
COOLDOWN

SKIPPED occurs when: account is inactive, no position found for exit, or outside trading hours. COOLDOWN occurs when the same payload is sent within the cooldown window.

Per request (trigger logs)

SUCCESS
PARTIAL
FAILED
PENDING
HALTED
DUPLICATE

SUCCESS: no account failed (also when no account is deployed). Skipped accounts do not count as failures.

PARTIAL: some accounts failed, or an entry went through but its take-profit levels could not all be placed.

FAILED: no account succeeded and at least one failed.

PENDING: still being processed.

HALTED: trading was halted platform-wide. The request is recorded and nothing was executed. Not a failure.

DUPLICATE: the request repeated an idempotency_key that was already used. It is recorded, nothing was placed, and it is not counted in the trigger totals.

Copy Groups

Copy Groups allow you to execute trades simultaneously across multiple member accounts. The group owner can perform actions on all members' deployed accounts.

How It Works

1. Create Group — Select broker, provide name and description

2. Deploy Your Accounts — Add your own accounts with multiplier

3. Share Access Code — Members join using the 8-character code

4. Execute Trades — All 6 manual actions available for member accounts

Member Settings

SettingDescription
multiplierPer-member trade size multiplier (default 1.0). Scales absolute quantities and fixed-amount sizing only — percentage entries and percentage partial exits are per-member already and are left unscaled.
is_activeToggle member participation on/off

qty_type: RISK_PCT is not available for copy groups. Copy-group orders are manual orders, and the terminal does not offer it; an order that asks for it anyway is refused with "RISK_PCT is not available for copy groups".

Owner Dashboard

As a group owner, you can view:

• Positions — Live positions for all members

• Balances — Real-time balances for all members

• Open Orders — Pending orders for all members

• Execution Logs — Complete trade history with per-order details

Invite-Only Groups

You can restrict group membership by enabling invite-only mode. Only users whose client_id is in the invite list can join the group.

Copy Trading

Discover and follow expert traders. Subscribe to their published webhooks and deploy your accounts to automatically copy their trades.

Subscribing to a Webhook

1. Browse the Marketplace or Copy Trading page to find strategies

2. Click Subscribe and enter the access code (if required)

3. Deploy your broker account to the subscribed webhook

4. All webhook triggers from the creator will execute on your account

Important

You cannot subscribe to your own webhooks. Your broker must match the webhook's broker type. Invite-only webhooks require your TradoConnectID to be in the invite list.

Marketplace

The marketplace lets you discover published strategies from other traders. As a creator, you can publish your webhooks and share your trading expertise.

For Creators

1. Publish Your Webhook — Set welcome message, choose public or invite-only

2. Add Strategy Details — Tagline, description, tags, performance metrics

3. List on Marketplace — Make your strategy discoverable

4. Share Access Code — Share with your community

Strategy Details

Published strategies can include detailed performance information:

Win Rate
Risk/Reward
Max Drawdown
Expt. returns
Total Returns
Min Margin Required
Total Trades
Sharpe Ratio
Sortino Ratio
Max Win Streak
Max Loss Streak
Performance Duration

Email Notifications

The platform sends email notifications for important events to keep you informed about your account activity.

Deployment Notifications

EventEmail Subject
Deploy
"Account Deployed — {Account} on {Webhook}"
Undeploy
"Account Removed — {Account} from {Webhook}"
Activate
"Deployment Activated — {Account} on {Webhook}"
Deactivate
"Deployment Deactivated — {Account} on {Webhook}"
Multiplier Change
"Multiplier Updated — {Account} on {Webhook}"

Each email includes: webhook name, exchange, account name, client ID, multiplier value, status, access type, who performed the action, and timestamp.

Trading Time Windows

Set specific hours during which your account should execute trades. Orders received outside the window are automatically skipped.

Configuration

• Set start_time and end_time in 24-hour format (HH:MM)

• Trades outside this window are SKIPPED with reason "Outside trading hours"

• Set both to null for 24/7 trading (default)

• Configured per-account from the Add broker page

Time Zone

Trading time windows are evaluated in the server's timezone (UTC). Make sure to convert your local time to UTC when configuring.

Algo Lab

Write Python strategies, backtest on real CoinDCX Futures data, and run them live — all from your browser. Full API reference, indicator library, and examples.

View docs

Connect by Trado — Built by Windigotrade Pvt Ltd