const res = await fetch('https://app.trdrs.co/api/exit-plans/{id}', {
method: 'PUT',
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${process.env.TRDRS_API_KEY}`,
},
body: JSON.stringify({
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": [
"futures"
],
"instruments": [
"ES"
]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": null,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": null,
"breakeven": {
"triggerDistance": 8,
"plusDistance": 0
},
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
}
}),
})
const data = await res.json()curl -X PUT 'https://app.trdrs.co/api/exit-plans/{id}' \
-H "Authorization: Bearer $TRDRS_API_KEY" \
-H 'content-type: application/json' \
-d '{"name":"Two rungs and a runner","revision":"q2Jm4XxT0aVnR7cLp1sZfE9d","applicability":{"assetClasses":["futures"],"instruments":["ES"]},"definition":{"unit":"ticks","quantity":2,"tif":"gtc","entryType":"limit","legs":[{"seq":1,"quantity":1,"stopDistance":12,"targetDistance":20,"breakeven":null,"trail":[]},{"seq":2,"quantity":1,"stopDistance":12,"targetDistance":null,"breakeven":{"triggerDistance":8,"plusDistance":0},"trail":[{"stepSeq":1,"triggerDistance":16,"trailDistance":8,"frequencyTicks":2}]}]}}'import requests
url = "https://app.trdrs.co/api/exit-plans/{id}"
payload = {
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": ["futures"],
"instruments": ["ES"]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": None,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": None,
"breakeven": {
"triggerDistance": 8,
"plusDistance": 0
},
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.trdrs.co/api/exit-plans/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Two rungs and a runner',
'revision' => 'q2Jm4XxT0aVnR7cLp1sZfE9d',
'applicability' => [
'assetClasses' => [
'futures'
],
'instruments' => [
'ES'
]
],
'definition' => [
'unit' => 'ticks',
'quantity' => 2,
'tif' => 'gtc',
'entryType' => 'limit',
'legs' => [
[
'seq' => 1,
'quantity' => 1,
'stopDistance' => 12,
'targetDistance' => 20,
'breakeven' => null,
'trail' => [
]
],
[
'seq' => 2,
'quantity' => 1,
'stopDistance' => 12,
'targetDistance' => null,
'breakeven' => [
'triggerDistance' => 8,
'plusDistance' => 0
],
'trail' => [
[
'stepSeq' => 1,
'triggerDistance' => 16,
'trailDistance' => 8,
'frequencyTicks' => 2
]
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.trdrs.co/api/exit-plans/{id}"
payload := strings.NewReader("{\n \"name\": \"Two rungs and a runner\",\n \"revision\": \"q2Jm4XxT0aVnR7cLp1sZfE9d\",\n \"applicability\": {\n \"assetClasses\": [\n \"futures\"\n ],\n \"instruments\": [\n \"ES\"\n ]\n },\n \"definition\": {\n \"unit\": \"ticks\",\n \"quantity\": 2,\n \"tif\": \"gtc\",\n \"entryType\": \"limit\",\n \"legs\": [\n {\n \"seq\": 1,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": 20,\n \"breakeven\": null,\n \"trail\": []\n },\n {\n \"seq\": 2,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": null,\n \"breakeven\": {\n \"triggerDistance\": 8,\n \"plusDistance\": 0\n },\n \"trail\": [\n {\n \"stepSeq\": 1,\n \"triggerDistance\": 16,\n \"trailDistance\": 8,\n \"frequencyTicks\": 2\n }\n ]\n }\n ]\n }\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://app.trdrs.co/api/exit-plans/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Two rungs and a runner\",\n \"revision\": \"q2Jm4XxT0aVnR7cLp1sZfE9d\",\n \"applicability\": {\n \"assetClasses\": [\n \"futures\"\n ],\n \"instruments\": [\n \"ES\"\n ]\n },\n \"definition\": {\n \"unit\": \"ticks\",\n \"quantity\": 2,\n \"tif\": \"gtc\",\n \"entryType\": \"limit\",\n \"legs\": [\n {\n \"seq\": 1,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": 20,\n \"breakeven\": null,\n \"trail\": []\n },\n {\n \"seq\": 2,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": null,\n \"breakeven\": {\n \"triggerDistance\": 8,\n \"plusDistance\": 0\n },\n \"trail\": [\n {\n \"stepSeq\": 1,\n \"triggerDistance\": 16,\n \"trailDistance\": 8,\n \"frequencyTicks\": 2\n }\n ]\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.trdrs.co/api/exit-plans/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Two rungs and a runner\",\n \"revision\": \"q2Jm4XxT0aVnR7cLp1sZfE9d\",\n \"applicability\": {\n \"assetClasses\": [\n \"futures\"\n ],\n \"instruments\": [\n \"ES\"\n ]\n },\n \"definition\": {\n \"unit\": \"ticks\",\n \"quantity\": 2,\n \"tif\": \"gtc\",\n \"entryType\": \"limit\",\n \"legs\": [\n {\n \"seq\": 1,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": 20,\n \"breakeven\": null,\n \"trail\": []\n },\n {\n \"seq\": 2,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": null,\n \"breakeven\": {\n \"triggerDistance\": 8,\n \"plusDistance\": 0\n },\n \"trail\": [\n {\n \"stepSeq\": 1,\n \"triggerDistance\": 16,\n \"trailDistance\": 8,\n \"frequencyTicks\": 2\n }\n ]\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"plan": {
"id": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": [
"futures"
],
"instruments": [
"ES"
]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": null,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": null,
"breakeven": {
"triggerDistance": 8,
"plusDistance": 0
},
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
},
"requires": [
"stop_loss",
"take_profit",
"runner_leg",
"breakeven",
"trailing_stop"
],
"updatedAt": 1787581400000
}
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "exit_plan_conflict",
"planId": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
"expectedRevision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"actualRevision": "Kb8vN2wY6tQ1rD5xLp0hUeAc"
}Replace an exit plan
Replaces a saved plan, conditionally. The body carries the revision the caller read: a save whose revision is not the stored one is refused with 409 and the revision the plan carries now, rather than silently overwriting an edit that arrived in between. There is no unconditional write.
const res = await fetch('https://app.trdrs.co/api/exit-plans/{id}', {
method: 'PUT',
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${process.env.TRDRS_API_KEY}`,
},
body: JSON.stringify({
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": [
"futures"
],
"instruments": [
"ES"
]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": null,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": null,
"breakeven": {
"triggerDistance": 8,
"plusDistance": 0
},
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
}
}),
})
const data = await res.json()curl -X PUT 'https://app.trdrs.co/api/exit-plans/{id}' \
-H "Authorization: Bearer $TRDRS_API_KEY" \
-H 'content-type: application/json' \
-d '{"name":"Two rungs and a runner","revision":"q2Jm4XxT0aVnR7cLp1sZfE9d","applicability":{"assetClasses":["futures"],"instruments":["ES"]},"definition":{"unit":"ticks","quantity":2,"tif":"gtc","entryType":"limit","legs":[{"seq":1,"quantity":1,"stopDistance":12,"targetDistance":20,"breakeven":null,"trail":[]},{"seq":2,"quantity":1,"stopDistance":12,"targetDistance":null,"breakeven":{"triggerDistance":8,"plusDistance":0},"trail":[{"stepSeq":1,"triggerDistance":16,"trailDistance":8,"frequencyTicks":2}]}]}}'import requests
url = "https://app.trdrs.co/api/exit-plans/{id}"
payload = {
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": ["futures"],
"instruments": ["ES"]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": None,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": None,
"breakeven": {
"triggerDistance": 8,
"plusDistance": 0
},
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.trdrs.co/api/exit-plans/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Two rungs and a runner',
'revision' => 'q2Jm4XxT0aVnR7cLp1sZfE9d',
'applicability' => [
'assetClasses' => [
'futures'
],
'instruments' => [
'ES'
]
],
'definition' => [
'unit' => 'ticks',
'quantity' => 2,
'tif' => 'gtc',
'entryType' => 'limit',
'legs' => [
[
'seq' => 1,
'quantity' => 1,
'stopDistance' => 12,
'targetDistance' => 20,
'breakeven' => null,
'trail' => [
]
],
[
'seq' => 2,
'quantity' => 1,
'stopDistance' => 12,
'targetDistance' => null,
'breakeven' => [
'triggerDistance' => 8,
'plusDistance' => 0
],
'trail' => [
[
'stepSeq' => 1,
'triggerDistance' => 16,
'trailDistance' => 8,
'frequencyTicks' => 2
]
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.trdrs.co/api/exit-plans/{id}"
payload := strings.NewReader("{\n \"name\": \"Two rungs and a runner\",\n \"revision\": \"q2Jm4XxT0aVnR7cLp1sZfE9d\",\n \"applicability\": {\n \"assetClasses\": [\n \"futures\"\n ],\n \"instruments\": [\n \"ES\"\n ]\n },\n \"definition\": {\n \"unit\": \"ticks\",\n \"quantity\": 2,\n \"tif\": \"gtc\",\n \"entryType\": \"limit\",\n \"legs\": [\n {\n \"seq\": 1,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": 20,\n \"breakeven\": null,\n \"trail\": []\n },\n {\n \"seq\": 2,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": null,\n \"breakeven\": {\n \"triggerDistance\": 8,\n \"plusDistance\": 0\n },\n \"trail\": [\n {\n \"stepSeq\": 1,\n \"triggerDistance\": 16,\n \"trailDistance\": 8,\n \"frequencyTicks\": 2\n }\n ]\n }\n ]\n }\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://app.trdrs.co/api/exit-plans/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Two rungs and a runner\",\n \"revision\": \"q2Jm4XxT0aVnR7cLp1sZfE9d\",\n \"applicability\": {\n \"assetClasses\": [\n \"futures\"\n ],\n \"instruments\": [\n \"ES\"\n ]\n },\n \"definition\": {\n \"unit\": \"ticks\",\n \"quantity\": 2,\n \"tif\": \"gtc\",\n \"entryType\": \"limit\",\n \"legs\": [\n {\n \"seq\": 1,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": 20,\n \"breakeven\": null,\n \"trail\": []\n },\n {\n \"seq\": 2,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": null,\n \"breakeven\": {\n \"triggerDistance\": 8,\n \"plusDistance\": 0\n },\n \"trail\": [\n {\n \"stepSeq\": 1,\n \"triggerDistance\": 16,\n \"trailDistance\": 8,\n \"frequencyTicks\": 2\n }\n ]\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.trdrs.co/api/exit-plans/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Two rungs and a runner\",\n \"revision\": \"q2Jm4XxT0aVnR7cLp1sZfE9d\",\n \"applicability\": {\n \"assetClasses\": [\n \"futures\"\n ],\n \"instruments\": [\n \"ES\"\n ]\n },\n \"definition\": {\n \"unit\": \"ticks\",\n \"quantity\": 2,\n \"tif\": \"gtc\",\n \"entryType\": \"limit\",\n \"legs\": [\n {\n \"seq\": 1,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": 20,\n \"breakeven\": null,\n \"trail\": []\n },\n {\n \"seq\": 2,\n \"quantity\": 1,\n \"stopDistance\": 12,\n \"targetDistance\": null,\n \"breakeven\": {\n \"triggerDistance\": 8,\n \"plusDistance\": 0\n },\n \"trail\": [\n {\n \"stepSeq\": 1,\n \"triggerDistance\": 16,\n \"trailDistance\": 8,\n \"frequencyTicks\": 2\n }\n ]\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"plan": {
"id": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": [
"futures"
],
"instruments": [
"ES"
]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": null,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": null,
"breakeven": {
"triggerDistance": 8,
"plusDistance": 0
},
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
},
"requires": [
"stop_loss",
"take_profit",
"runner_leg",
"breakeven",
"trailing_stop"
],
"updatedAt": 1787581400000
}
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "invalid_instrument"
}{
"error": "exit_plan_conflict",
"planId": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
"expectedRevision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"actualRevision": "Kb8vN2wY6tQ1rD5xLp0hUeAc"
}Authorizations
Your firm’s API key (the API calls this the tenant key; trdrs_sk_…), server-to-server only.
Path Parameters
Body
Author or replace a plan. A replacement carries revision: the value the caller read. A revision that is not the stored one is refused with 409 rather than overwriting an edit nobody saw.
WireExitPlanDefinition (@trdrs/contracts): the structured plan — everything the engine needs to resolve concrete legs, and nothing about an account, a venue or a price. unit says what the distances mean; price and currency are resolved to ticks by the engine against the account's own instrument facts. quantity is what the ladder was authored for: an order may carry more, and the surplus is an unmanaged remainder the plan never protects.
Show child attributes
Show child attributes
{
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": null,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": null,
"breakeven": { "triggerDistance": 8, "plusDistance": 0 },
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
}
Required on a replacement; ignored on a create.
Show child attributes
Show child attributes
Response
The plan as saved
WireSavedExitPlan (@trdrs/contracts): one saved plan. revision is opaque — echo back exactly the value you read on a save or a delete, and never construct one. requires is what the plan needs an account to support, derived from the plan itself, so a host can tell which plans a selected account can run.
Show child attributes
Show child attributes
{
"id": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
"name": "Two rungs and a runner",
"revision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
"applicability": {
"assetClasses": ["futures"],
"instruments": ["ES"]
},
"definition": {
"unit": "ticks",
"quantity": 2,
"tif": "gtc",
"entryType": "limit",
"legs": [
{
"seq": 1,
"quantity": 1,
"stopDistance": 12,
"targetDistance": 20,
"breakeven": null,
"trail": []
},
{
"seq": 2,
"quantity": 1,
"stopDistance": 12,
"targetDistance": null,
"breakeven": { "triggerDistance": 8, "plusDistance": 0 },
"trail": [
{
"stepSeq": 1,
"triggerDistance": 16,
"trailDistance": 8,
"frequencyTicks": 2
}
]
}
]
},
"requires": [
"stop_loss",
"take_profit",
"runner_leg",
"breakeven",
"trailing_stop"
],
"updatedAt": 1787581400000
}