> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trdrs.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Save and apply exit plans

> Author a ladder once, preview it against an account, then place by reference — never by retyped levels.

An exit plan is a saved ladder: how much comes off at each rung, where the stop sits, whether the
stop moves to breakeven, whether it trails. It belongs to the person who authored it and to no
account, so the same ladder applies to whichever account is selected.

The point of the whole surface is that levels are never retyped. You preview the plan against a
real account and a real order, and you place against the token that preview gave you.

<Steps>
  <Step title="Author the plan">
    [Create an exit plan](/api-reference/account/create-an-exit-plan) takes a name, an optional
    applicability filter, and the definition. It returns the plan with its `revision`, because the
    next thing you do is edit it and you need the revision to do so.

    ```bash theme={null}
    curl -X POST "$TRDRS_API_BASE_URL/api/exit-plans" \
      -H "Authorization: Bearer $TRDRS_TENANT_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Two rungs and a runner",
        "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 }]
            }
          ]
        }
      }'
    ```

    The definition is validated on write. A `400` means it broke one of the plan invariants:

    * every leg carries a stop — a plan cannot save an unprotected rung
    * targets widen down the ladder
    * stops do not tighten down the ladder
    * a trail only tightens
    * at most one leg is a runner (a leg with no `targetDistance`, held with a stop and nothing else)
  </Step>

  <Step title="List what you have, and what an account can run">
    ```bash theme={null}
    curl "$TRDRS_API_BASE_URL/api/exit-plans" \
      -H "Authorization: Bearer $TRDRS_TENANT_KEY"
    ```

    Each plan carries `requires` — what it needs an account to support, derived from the plan
    itself. Compare it against `capabilities.exitPlanSupport` on the selected account (from [List
    accounts](/api-reference/account/list-accounts) or the snapshot) and offer only the plans that
    will actually run. Both use the same tokens: `stop_loss`, `take_profit`, `multiple_targets`,
    `runner_leg`, `breakeven`, `trailing_stop`.
  </Step>

  <Step title="Edit and delete conditionally">
    Both writes carry the revision you read. There is no unconditional write.

    ```bash theme={null}
    curl -X PUT "$TRDRS_API_BASE_URL/api/exit-plans/0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37" \
      -H "Authorization: Bearer $TRDRS_TENANT_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": 24, "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 }]
            }
          ]
        }
      }'
    ```

    A replacement is the whole plan, not a patch — send the definition you want to end up with.

    A delete puts the revision in the query string:

    ```bash theme={null}
    curl -X DELETE "$TRDRS_API_BASE_URL/api/exit-plans/0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37?revision=q2Jm4XxT0aVnR7cLp1sZfE9d" \
      -H "Authorization: Bearer $TRDRS_TENANT_KEY"
    ```

    A stale revision is refused with `409` and an `exit_plan_conflict` body carrying
    `expectedRevision` and `actualRevision`, so you can show the difference rather than only the
    refusal. Revisions are opaque: echo back exactly what you read, and never construct one.
  </Step>

  <Step title="Preview it against the account and the order">
    [Preview an exit plan](/api-reference/account/preview-an-exit-plan) resolves every leg from that
    account's own instrument facts and returns the token that binds the placement. The request
    names the order and nothing else — the engine supplies every price.

    ```bash theme={null}
    curl -X POST "$TRDRS_API_BASE_URL/api/account/exit-plans/preview" \
      -H "Authorization: Bearer $TRDRS_TENANT_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "planId": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
        "clientOrderId": "entry-esu6-1787580900",
        "instrument": "ESU6",
        "side": "buy",
        "quantity": 2,
        "entryType": "limit",
        "entryPrice": 6480.5
      }'
    ```

    Read three things off the response before you show it:

    * `legs` — each with both the tick distance and the absolute price, so a client renders one and
      the venue takes the other.
    * `managedQuantity` and `unmanagedQuantity` — the ladder was authored for a quantity, and an
      order may carry more. The surplus is an unmanaged remainder the plan never protects. Show it.
    * `engineManaged` — true when the engine itself will ratchet the stop, rather than the venue
      holding it still.

    The token expires at `expiresAt`, and it is bound to the `clientOrderId` you sent, so a
    confirmation is spent on one submission rather than being good for any order until it lapses.
    A market entry's levels are indicative: its ladder is measured from the mark at placement.
  </Step>

  <Step title="Place by reference">
    Send `exitPlan` on [Place an order](/api-reference/trading/place-an-order) — the plan, the
    revision you previewed, and the token you were given. No levels.

    ```bash theme={null}
    curl -X POST "$TRDRS_API_BASE_URL/api/trading/order" \
      -H "Authorization: Bearer $TRDRS_TENANT_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "instrument": "ESU6",
        "side": "buy",
        "qty": 2,
        "clientOrderId": "entry-esu6-1787580900",
        "orderType": "limit",
        "limitPrice": 6480.5,
        "exitPlan": {
          "planId": "0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37",
          "planRevision": "q2Jm4XxT0aVnR7cLp1sZfE9d",
          "previewToken": "WyI3YTFmNGM5M2IyOGQwNWU2Il0.9Qp3Vv1sKdN0yTbXmR7cLh"
        }
      }'
    ```

    The engine reloads the plan at that revision and re-resolves it. It refuses an edited plan, a
    deleted one, a changed account, drift, or an expiry.
  </Step>
</Steps>

## Why the token, and not the prices

The token is a signed binding over the order — the account, the client order id, the plan and its
revision, the instrument, the side, the quantity and the entry. It is never a binding over the
prices. Placement reloads the plan and re-resolves the levels, so the preview proves what was
agreed rather than carrying a price a client could have chosen.

That is also why `exitPlan` and the plain `stopLoss`/`takeProfit` legs are mutually exclusive:
sending both answers `400`. One order has one source of truth for its exits.

## Warnings you have to surface

A `200` from the order route can still carry `warnings`. Two codes belong to this surface:

| Code                           | What happened                                                                                              |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `exit_plan_remainder_unplaced` | Part of the order's quantity was not covered by the ladder. `requestedQty` and `placedQty` say how much.   |
| `exit_plan_not_recorded`       | The exits were placed but the engine did not record the managed instance, so it is not auto-managing them. |

## After the fill

[List server-managed stops](/api-reference/account/list-server-managed-stops) shows the instances
the engine is running. Each carries `planId` and `planRevision` — a receipt for the revision that
instance accepted. The definition it runs was frozen then, so editing the saved plan cannot reach
an already-open position.

## Where to go deeper

* [Protect a position](/guides/protect-a-position) — the plain stop-and-target path, without a plan.
* [Place your first order](/guides/place-your-first-order) — where `exitPlan` sits in the order body.
* [List position exits](/api-reference/account/list-position-exits) — what the plan actually placed.
* [Errors](/partner-platform/overview/errors) — `409` and the conflict shape in full.
