Webhook API v2 | Valuera
Envelope, actions, and TradingView alert format for Valuera webhook ingest.
Webhook API v2
Webhook API v2.0 documentation — exported from https://docs.valuera.cloud/webhook
Endpoints
- Create a webhook endpoint in the VALUERA portal (Customer Ingress or Provider).
- TradingView: POST https://valuera.cloud/tv/{id} — server-injected token, no custom headers.
- Scripts/API: POST https://valuera.cloud/webhook/{id} — header X-Webhook-Token: <token>.
- Optional HMAC: same API URLs + X-Signature and X-Timestamp headers.
- JSON id must match {id} in the URL.
Envelope
{
"id": "your-endpoint-key",
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"action": "OPEN"
}
Actions
OPEN
Opens one copy-trading position with symbol, side, entry, SL, and TP (one signal = one position; TP target from strategy).
What's new in v2
- order_type limit or stop places a real pending order on the copier account, instead of being converted to market or skipped.
- SL and TP violating the broker minimum distance are moved to the first legal price instead of failing the order.
- Volume is never sent nor copied: lot size is decided by the receiving account strategy.
{
"id": "your-endpoint-key",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"action": "OPEN",
"symbol": "XAUUSD",
"side": "BUY",
"entry": 2650.5,
"sl": 2640,
"tp": [
2660,
2670
]
}
| Field | Required | Description | ||
|---|---|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. | ||
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. | ||
| `action` | yes | Operation to execute (see sidebar). | ||
| `symbol` | yes | MT5 symbol (e.g. XAUUSD). | ||
| `side` | yes | BUY or SELL. | ||
| `entry` | yes | Entry price (number, {min,max} range, or [lo,hi] array). entry_price alias rejected. | ||
| `sl` | yes | Stop loss. | ||
| `tp` | yes | Take profit: number or array of numbers. | ||
| `market_price` | no | Market price for entry zone resolution. | ||
| `order_type` | no | market | limit | stop (default market). |
| `pip_size` | no | Override pip size for the symbol. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.400 invalid-action— Unrecognized action.400 invalid-side— side must be BUY or SELL.400 missing-symbol— symbol missing or empty.400 missing-open-fields— Missing entry, sl, or tp.409 no-dispatch— Valid payload but no account routing enabled for OPEN.
v1 behaviour (still supported)
- In v1 an order_type limit with entry outside the tolerance band was skipped with far-from-market-skip: no position and no pending order.
CLOSE_ALL
Closes all open positions on linked accounts. Does not accept symbol.
{
"id": "your-endpoint-key",
"request_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"action": "CLOSE_ALL"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.400 close-all-symbol-forbidden— CLOSE_ALL must not include symbol — use CLOSE_SYMBOL.
CLOSE_SYMBOL
Closes all open positions for a specific symbol.
{
"id": "your-endpoint-key",
"request_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"action": "CLOSE_SYMBOL",
"symbol": "XAUUSD"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `symbol` | yes | Symbol to close. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.400 missing-symbol— symbol required for CLOSE_SYMBOL.
CLOSE_TICKET
Closes the position linked to an open_request_id (ticket correlated from a prior OPEN).
What's new in v2
- With tickets the close is exact even when the broker truncated the position comment.
- Position already closed (SL or TP hit): the request is a no-op, not an error.
- If the ticket is still an unfilled pending order, the order is cancelled.
- No symbol fallback: if the ticket cannot be resolved, nothing is closed.
{
"id": "your-endpoint-key",
"request_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
"action": "CLOSE_TICKET",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `open_request_id` | yes | UUID of the original OPEN (returned or sent open_request_id). |
| `tickets` | no | v2 — explicit MT5 ticket array. Takes precedence over open_request_id. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.400 missing-open-request-id— open_request_id required for CLOSE_TICKET.
v1 behaviour (still supported)
- In v1 the ticket was resolved from the internal registry only and, when the match was missing, the close could fall back to all positions on the symbol. In v2 that fallback is removed.
MOVE_SL_BE
Moves stop loss to break-even. With open_request_id/tickets only those positions; otherwise by symbol (or whole account if symbol is omitted).
What's new in v2
- With open_request_id or tickets the stop moves only on those positions.
- If break-even violates the broker minimum distance the stop is moved to the first legal price: in that case it is not exact break-even but the closest allowed level.
{
"id": "your-endpoint-key",
"request_id": "e5f6a7b8-c9d0-1234-ef01-345678901234",
"action": "MOVE_SL_BE",
"symbol": "XAUUSD"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `symbol` | no | If omitted (and no ticket), applies to all eligible positions. |
| `open_request_id` | no | v2 — UUID of the original OPEN: the action only touches the linked position. If omitted, v1 semantics apply (all positions on the symbol). |
| `tickets` | no | v2 — explicit MT5 ticket array. Takes precedence over open_request_id. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.
v1 behaviour (still supported)
- Without ticket identity the behaviour is v1: all positions on the symbol, and all account positions when symbol is omitted.
MOVE_SL_PRICE
Moves stop loss to a fixed price. With open_request_id/tickets only those positions.
What's new in v2
- With open_request_id or tickets the stop moves only on those positions.
- An sl_price beyond the allowed minimum distance is moved to the first legal price instead of being rejected.
{
"id": "your-endpoint-key",
"request_id": "f6a7b8c9-d0e1-2345-f012-456789012345",
"action": "MOVE_SL_PRICE",
"sl_price": 2655,
"symbol": "XAUUSD"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `sl_price` | yes | New stop loss price. |
| `symbol` | no | Filter by symbol (optional). |
| `open_request_id` | no | v2 — UUID of the original OPEN: the action only touches the linked position. If omitted, v1 semantics apply (all positions on the symbol). |
| `tickets` | no | v2 — explicit MT5 ticket array. Takes precedence over open_request_id. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.
v1 behaviour (still supported)
- Without ticket identity the v1 per-symbol semantics apply, unchanged.
MODIFY
Updates stop loss and take profit of the linked position in a single request.
What's new in v2
- New action in v2: previously take profit could not be modified by signal, only MOVE_SL_BE and MOVE_SL_PRICE existed.
- sl and tp travel together in a single modification, so the position is never left in an intermediate state.
- sl: 0 removes the stop only if the provider explicitly opted in to trade without stops; otherwise the removal is ignored.
{
"id": "your-endpoint-key",
"request_id": "d0e1f2a3-b4c5-6789-3456-890123456789",
"action": "MODIFY",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"sl": 2645,
"tp": [2665]
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `open_request_id` | no | v2 — UUID of the original OPEN: the action only touches the linked position. If omitted, v1 semantics apply (all positions on the symbol). |
| `tickets` | no | v2 — explicit MT5 ticket array. Takes precedence over open_request_id. |
| `sl` | no | New stop loss. Omitted leaves the current stop unchanged. |
| `tp` | no | New take profit: number or array. Omitted leaves the current target unchanged. |
| `symbol` | no | Filters by symbol when no ticket identity is provided. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.400 modify-nothing-to-do— Neither sl nor tp provided: nothing to modify.
PARTIALS
Closes a percentage of open positions. With open_request_id/tickets only those positions.
What's new in v2
- The percentage applies to the receiving position volume, not the originating one.
- If the remainder would fall below the broker minimum lot, the position is fully closed instead of failing.
- close_percent 100 is not allowed: use CLOSE_TICKET.
{
"id": "your-endpoint-key",
"request_id": "a7b8c9d0-e1f2-3456-0123-567890123456",
"action": "PARTIALS",
"close_percent": 50,
"symbol": "XAUUSD"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `close_percent` | yes | Percentage to close (e.g. 50 = 50%). |
| `symbol` | yes | MT5 symbol to partially close. |
| `open_request_id` | no | v2 — UUID of the original OPEN: the action only touches the linked position. If omitted, v1 semantics apply (all positions on the symbol). |
| `tickets` | no | v2 — explicit MT5 ticket array. Takes precedence over open_request_id. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.400 missing-symbol— symbol required for PARTIALS.
v1 behaviour (still supported)
- Without ticket identity the reduction hits all positions on the symbol, as in v1.
CANCEL_PENDING
Cancels pending orders. With open_request_id/tickets only that one; otherwise by symbol (or all if symbol is omitted).
What's new in v2
- With ticket identity only that pending order is cancelled.
- If the pending order was already filled, the resulting position is closed, so no orphan positions remain.
{
"id": "your-endpoint-key",
"request_id": "b8c9d0e1-f2a3-4567-1234-678901234567",
"action": "CANCEL_PENDING",
"symbol": "XAUUSD"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
| `symbol` | no | If omitted (and no ticket), cancels pending on all symbols. |
| `open_request_id` | no | v2 — UUID of the original OPEN: the action only touches the linked position. If omitted, v1 semantics apply (all positions on the symbol). |
| `tickets` | no | v2 — explicit MT5 ticket array. Takes precedence over open_request_id. |
Success response (200)
{
"ok": true,
"dispatched": 2,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"open_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.
v1 behaviour (still supported)
- Without ticket identity it cancels all pending orders on the symbol, or all account pending orders when symbol is omitted.
PING
Checks connectivity and auth without executing trades.
{
"id": "your-endpoint-key",
"request_id": "c9d0e1f2-a3b4-5678-2345-789012345678",
"action": "PING"
}
| Field | Required | Description |
|---|---|---|
| `id` | yes | Endpoint key; must match {id} in the URL. |
| `request_id` | yes | Stable UUID v4 assigned by VALUERA per endpoint (shown in panel). Must match your endpoint's id. |
| `action` | yes | Operation to execute (see sidebar). |
Success response (200)
{
"ok": true,
"dispatched": 0,
"request_id": "c9d0e1f2-a3b4-5678-2345-789012345678",
"ping": true
}
Main errors
400 missing-id— Body missing id.400 id-mismatch— Body id ≠ URL endpoint key.400 missing-request-id— request_id missing.400 invalid-request-id— request_id is not a valid UUID v4.400 request-id-mismatch— Body request_id ≠ endpoint stable UUID.401 token-mismatch— Wrong or missing X-Webhook-Token (/webhook/ route).404 endpoint-not-found— Endpoint disabled or not found.429 rate-limited— Too many requests from same IP/endpoint.
TradingView
- Copy the /tv/{id} URL and stable request_id from the webhook ingress panel.
- TradingView → Alert → Notifications → Webhook URL: paste the URL.
- Alert message = compact JSON (max ~4096 chars) with the panel's fixed request_id.
- Do not change request_id between alerts — it identifies the endpoint.
- For OPEN use TradingView placeholders ({{close}}, {{plot_0}}, …) where needed.
Code samples
python
import requests
URL = "https://valuera.cloud/webhook/YOUR_KEY"
TOKEN = "YOUR_TOKEN"
payload = {
"id": "YOUR_KEY",
"request_id": "YOUR_STABLE_REQUEST_ID",
"action": "OPEN",
"symbol": "XAUUSD",
"side": "BUY",
"entry": 2650.50,
"sl": 2640.00,
"tp": [2660.00, 2670.00],
}
r = requests.post(URL, json=payload, headers={"X-Webhook-Token": TOKEN}, timeout=15)
print(r.status_code, r.json())
javascript
const res = await fetch("https://valuera.cloud/webhook/YOUR_KEY", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Webhook-Token": "YOUR_TOKEN",
},
body: JSON.stringify({
id: "YOUR_KEY",
request_id: "YOUR_STABLE_REQUEST_ID",
action: "OPEN",
symbol: "XAUUSD",
side: "BUY",
entry: 2650.5,
sl: 2640,
tp: [2660, 2670],
}),
});
console.log(res.status, await res.json());
curl
curl -sS -X POST "https://valuera.cloud/webhook/YOUR_KEY" \
-H "Content-Type: application/json" \
-H "X-Webhook-Token: YOUR_TOKEN" \
-d '{"id":"YOUR_KEY","request_id":"550e8400-e29b-41d4-a716-446655440000","action":"PING"}'
go
package main
import (
"bytes"
"encoding/json"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]any{
"id": "YOUR_KEY", "request_id": "YOUR_STABLE_REQUEST_ID",
"action": "PING",
})
req, _ := http.NewRequest("POST", "https://valuera.cloud/webhook/YOUR_KEY", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Webhook-Token", "YOUR_TOKEN")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}
php
<?php
$payload = [
'id' => 'YOUR_KEY',
'request_id' => 'YOUR_STABLE_REQUEST_ID',
'action' => 'PING',
];
$ch = curl_init('https://valuera.cloud/webhook/YOUR_KEY');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Webhook-Token: YOUR_TOKEN'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch);
Webhook API v2.0 · 2026-07-30