> ## 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.

# 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.



## OpenAPI

````yaml /partner-platform/openapi.json put /api/exit-plans/{id}
openapi: 3.1.0
info:
  title: trdrs Engine API
  version: 1.1.0
  description: >-
    ## API Reference


    This is the served OpenAPI contract for the trdrs engine: market data,
    trading and account

    routes for your firm's traders, trdrs Connect account-registration handoff,
    and preview

    challenge routes.


    See Quick Start for the first integration path: key setup, market config,
    chart data, Connect

    account registrations, idempotency, stream reconnects, and conformance.


    See Overview and API Standards for the cross-cutting contract rules.
servers:
  - url: https://app.trdrs.co
    description: Production
  - url: /
    description: This engine
security: []
tags:
  - name: Market data
    description: >-
      Symbol search and resolution, OHLCV history, quote snapshots, the server
      clock, and the live bar stream. Crypto rides each venue’s public feed;
      futures stream from the caller’s own connected Rithmic account. With none
      connected, futures requests answer 503 `feed_requires_connection`.
  - name: News
    description: >-
      Aggregated market news and the economic calendar, from licensed/open
      sources, keyword-tagged with futures roots at ingest. Platform-wide
      content (nothing per-user), admitted exactly like Market data: a licensed
      origin, a session, or a firm API key. Headlines page by published time,
      scope by instrument root, and stream live over SSE; thumbnails serve
      through the image proxy.
  - name: Trading
    description: >-
      The money surface: entries, exits, replaces, cancels, and position/account
      flattening. Every order-placing call uses `clientOrderId` as its
      idempotency key.
  - name: Account
    description: >-
      Reading a connected account. You do not create trading accounts here: a
      trader connects their own broker account (or creates a free demo account)
      in the app, and firms create evaluation accounts through the Partner API
      (Firm accounts → Create evaluation accounts) or register venue accounts
      through Connect (Create an account registration). Account state and the
      durable ledgers: balances, positions, working orders, fills, P&L history,
      and the live account stream.
  - name: Connect
    description: >-
      trdrs Connect account registration, for partner firms. Register an account
      you issued on your own venue — a pending account registration — with the
      trader’s sign-in email, optionally the venue account id and the login name
      your venue issued. The trader finds it waiting in the connect flow the
      moment they sign in with that email: the connect step is pre-filled with
      everything except the credential, which the trader always enters
      themselves. A registration never transmits a password and never grants
      access to anything before the trader’s own login succeeds. These routes
      answer a partner-scoped key only; a firm API key or a user session gets
      401. Registrations expire after 30 days; re-registering the same email +
      account refreshes the expiry instead of duplicating. The end-to-end flow
      guide is **[Quick Start](/docs/guides/quick-start)**.
  - name: Firm accounts
    description: >-
      Evaluation accounts your firm issues on the trdrs venue, through your
      partner key — the other half of account setup. Connect registrations hand
      off accounts that exist on your venue; these routes create and manage
      accounts on ours: the trader trades them on trdrs, and your firm owns the
      lifecycle. Every route is scoped to accounts your firm created through
      this API — an account the same trader opened themselves is invisible and
      untouchable here, by construction. Creation is batched with per-item
      results, and every write carries your own `referenceId`, so a crashed
      pipeline retries safely. Served when the deployment runs the prop engine;
      without it, every route in this group answers `404`.
  - name: Webhooks
    description: >-
      The outbound event bus: register an https endpoint and the platform pushes
      events to it instead of your back office polling us. Every delivery is
      signed (`trdrs-signature: t=<unix>,v1=<hmac-sha256>` over
      `${t}.${rawBody}`) so you can prove it came from us and is fresh, and
      every delivery is durable — a failed attempt is retried with backoff for
      about nine hours and the whole log is readable, so an endpoint that was
      down is a delay rather than a lost event. Serves brokers and prop firms
      alike: the account-registration (`registration.*`) events fire wherever
      Connect does, and the account events fire where the prop engine runs.
  - name: Challenges
    description: >-
      The prop evaluation surface: challenge programs and a trader’s own
      enrollments. **Preview: the one group on this page outside the
      additive-only guarantee** (the pre-contract v1 scaffold; the Phase-1
      rebuild will change these shapes; see Stability). **Cookie-authenticated,
      not key-authenticated**, and served only when the engine runs with
      `CHALLENGES_ENABLED`; without that flag the bundle is absent and every
      route below returns `404`. The firm-console/admin half of this surface is
      deliberately not documented here. It is back office, not licensed surface.
paths:
  /api/exit-plans/{id}:
    put:
      tags:
        - Account
      summary: Replace an exit plan
      description: >-
        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.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExitPlanWriteRequest'
      responses:
        '200':
          description: The plan as saved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExitPlanResponse'
        '400':
          description: The definition breaks a plan invariant, or no revision was sent
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing/unknown/revoked credential
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: No such exit plan
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: The plan changed since it was read
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExitPlanConflict'
      security:
        - tenantKey: []
      x-codeSamples:
        - lang: javascript
          label: TypeScript
          source: >-
            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()
        - lang: shell
          label: cURL
          source: |-
            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}]}]}}'
components:
  schemas:
    ExitPlanWriteRequest:
      type: object
      description: >-
        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.
      properties:
        name:
          type: string
        revision:
          type: string
          description: Required on a replacement; ignored on a create.
        applicability:
          type: object
          properties:
            assetClasses:
              type: array
              items:
                type: string
            instruments:
              type: array
              items:
                type: string
        definition:
          $ref: '#/components/schemas/ExitPlanDefinition'
      required:
        - name
        - definition
      example:
        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
    ExitPlanResponse:
      type: object
      properties:
        plan:
          $ref: '#/components/schemas/SavedExitPlan'
      required:
        - plan
      example:
        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
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
      required:
        - error
      example:
        error: invalid_instrument
    ExitPlanConflict:
      type: object
      description: >-
        WireExitPlanConflict (@trdrs/contracts): the plan changed between the
        read and the write. It reports what the plan is now, so a client can
        show the difference rather than only the refusal.
      properties:
        error:
          type: string
          enum:
            - exit_plan_conflict
        planId:
          type: string
        expectedRevision:
          type: string
        actualRevision:
          type:
            - string
            - 'null'
      required:
        - error
        - planId
        - expectedRevision
      example:
        error: exit_plan_conflict
        planId: 0f6c2d18-7b4a-4a3e-9d21-8c5e4b0a9f37
        expectedRevision: q2Jm4XxT0aVnR7cLp1sZfE9d
        actualRevision: Kb8vN2wY6tQ1rD5xLp0hUeAc
    ExitPlanDefinition:
      type: object
      description: >-
        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.
      properties:
        unit:
          type: string
          enum:
            - ticks
            - price
            - currency
        quantity:
          type: number
        tif:
          type: string
        entryType:
          type: string
          enum:
            - market
            - limit
            - stop
            - stop_limit
        legs:
          type: array
          items:
            $ref: '#/components/schemas/ExitPlanLeg'
      required:
        - unit
        - quantity
        - tif
        - entryType
        - legs
      example:
        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
    SavedExitPlan:
      type: object
      description: >-
        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.
      properties:
        id:
          type: string
        name:
          type: string
        revision:
          type: string
        applicability:
          type: object
          properties:
            assetClasses:
              type: array
              items:
                type: string
            instruments:
              type: array
              items:
                type: string
          required:
            - assetClasses
            - instruments
        definition:
          $ref: '#/components/schemas/ExitPlanDefinition'
        requires:
          type: array
          items:
            type: string
            enum:
              - stop_loss
              - take_profit
              - multiple_targets
              - runner_leg
              - breakeven
              - trailing_stop
        updatedAt:
          type: integer
          description: Epoch milliseconds
      required:
        - id
        - name
        - revision
        - applicability
        - definition
        - requires
        - updatedAt
      example:
        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
    ExitPlanLeg:
      type: object
      description: >-
        WireExitPlanLeg (@trdrs/contracts): one rung of the ladder. Every leg
        carries a stop, because a plan cannot save an unprotected rung. A leg
        with no `targetDistance` is a runner: held with a stop and nothing else,
        and a plan holds at most one.
      properties:
        seq:
          type: integer
        quantity:
          type: number
        stopDistance:
          type: number
        targetDistance:
          type:
            - number
            - 'null'
        breakeven:
          oneOf:
            - $ref: '#/components/schemas/ExitPlanBreakeven'
            - type: 'null'
        trail:
          type: array
          items:
            $ref: '#/components/schemas/ExitPlanTrailStep'
      required:
        - seq
        - quantity
        - stopDistance
        - trail
      example:
        seq: 2
        quantity: 1
        stopDistance: 12
        targetDistance: null
        breakeven:
          triggerDistance: 8
          plusDistance: 0
        trail:
          - stepSeq: 1
            triggerDistance: 16
            trailDistance: 8
            frequencyTicks: 2
    ExitPlanBreakeven:
      type: object
      description: >-
        WireExitPlanBreakeven (@trdrs/contracts): a one-shot move of the stop to
        the entry plus `plusDistance`, once the position is `triggerDistance` in
        profit. Zero is exact breakeven.
      properties:
        triggerDistance:
          type: number
        plusDistance:
          type: number
      required:
        - triggerDistance
        - plusDistance
      example:
        triggerDistance: 8
        plusDistance: 0
    ExitPlanTrailStep:
      type: object
      description: >-
        WireExitPlanTrailStep (@trdrs/contracts): one tier of a trailing stop.
        Once the position is `triggerDistance` in profit the stop follows the
        best price by `trailDistance`, re-issued only after it has advanced a
        whole `frequencyTicks`. The frequency throttles venue calls, so it is
        always whole ticks whatever unit the distances are in. Tiers ascend by
        trigger and can only tighten.
      properties:
        stepSeq:
          type: integer
        triggerDistance:
          type: number
        trailDistance:
          type: number
        frequencyTicks:
          type: integer
      required:
        - stepSeq
        - triggerDistance
        - trailDistance
        - frequencyTicks
      example:
        stepSeq: 1
        triggerDistance: 16
        trailDistance: 8
        frequencyTicks: 2
  securitySchemes:
    tenantKey:
      type: http
      scheme: bearer
      description: >-
        Your firm’s API key (the API calls this the `tenant` key; `trdrs_sk_…`),
        server-to-server only.

````