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

# Create an enrollment

> **Preview: outside the additive-only guarantee.** These shapes are the pre-contract v1 scaffold; the Phase-1 rebuild will change them. Read them, do not pin to them.

**Served only when the engine runs with `CHALLENGES_ENABLED`.** The route bundle is not merely disabled without it. It is never constructed, so every path here answers `404`.

Enrols the calling user in a challenge: issues the evaluation account, creates the enrollment, and records the opening balance-ledger entry. `size` must be one of the program’s `accountSizes`. A program with a non-zero `priceCents` answers `402`: this engine collects no fee, so only a `0`-priced program enrols here. Atomic: the account, the enrollment, and the ledger entry are created as one unit.



## OpenAPI

````yaml /partner-platform/openapi.json post /api/challenges/enroll
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/challenges/enroll:
    post:
      tags:
        - Challenges
      summary: Create an enrollment
      description: >-
        **Preview: outside the additive-only guarantee.** These shapes are the
        pre-contract v1 scaffold; the Phase-1 rebuild will change them. Read
        them, do not pin to them.


        **Served only when the engine runs with `CHALLENGES_ENABLED`.** The
        route bundle is not merely disabled without it. It is never constructed,
        so every path here answers `404`.


        Enrols the calling user in a challenge: issues the evaluation account,
        creates the enrollment, and records the opening balance-ledger entry.
        `size` must be one of the program’s `accountSizes`. A program with a
        non-zero `priceCents` answers `402`: this engine collects no fee, so
        only a `0`-priced program enrols here. Atomic: the account, the
        enrollment, and the ledger entry are created as one unit.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChallengeEnrollRequest'
      responses:
        '200':
          description: Enrolled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChallengeEnrollResponse'
        '400':
          description: >-
            Missing/invalid `challengeId` or `size`, a `size` outside the
            program’s set, or no trading profile
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Not authenticated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: >-
            The program has a non-zero `priceCents`, and this engine collects no
            fee
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: No active challenge with that id, or `CHALLENGES_ENABLED` is off
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            The caller already holds a `registered` or `in_progress` enrollment
            in this program
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - sessionCookie: []
      x-codeSamples:
        - lang: javascript
          label: TypeScript
          source: >-
            // First-party cookie auth: this runs in a signed-in trdrs session,
            not under an API key.

            const res = await
            fetch('https://app.trdrs.co/api/challenges/enroll', {
              method: 'POST',
              headers: {
                'content-type': 'application/json',
              },
              credentials: 'include',
              body: JSON.stringify({
                "challengeId": "3f8a1c2e-9b47-4d10-a3fe-2c61b7c90d84",
                "size": 50000
              }),
            })

            const data = await res.json()
        - lang: shell
          label: cURL
          source: |-
            curl -X POST 'https://app.trdrs.co/api/challenges/enroll' \
              -b "session=$TRDRS_SESSION" \
              -H 'content-type: application/json' \
              -d '{"challengeId":"3f8a1c2e-9b47-4d10-a3fe-2c61b7c90d84","size":50000}'
components:
  schemas:
    ChallengeEnrollRequest:
      type: object
      properties:
        challengeId:
          type: string
          format: uuid
        size:
          type: integer
          description: Starting balance in whole dollars.
      required:
        - challengeId
        - size
      example:
        challengeId: 3f8a1c2e-9b47-4d10-a3fe-2c61b7c90d84
        size: 50000
    ChallengeEnrollResponse:
      type: object
      properties:
        enrollment:
          $ref: '#/components/schemas/WireEnrollment'
      required:
        - enrollment
      example:
        enrollment:
          id: e5c90b1a-7d34-4f6b-8a2e-91c8f0d47a53
          challengeId: 3f8a1c2e-9b47-4d10-a3fe-2c61b7c90d84
          challengeName: 50K Evaluation
          stage: 1
          accountNumber: EVAL-50K-0042
          type: standard
          status: registered
          startingBalance: 50000
          ddMode: trailing_max_equity_eod
          startsAt: null
          endsAt: null
          failReason: null
          createdAt: 1787058000
          progress:
            equity: 50000
            balance: 50000
            dayAnchorEquity: 50000
            hwmEquity: 50000
            dailyFloor: 48000
            totalFloor: 46000
            profitTargetLevel: 54000
            tradingDays: 0
            minTradingDays: 5
            openPositions: 0
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
      required:
        - error
      example:
        error: invalid_instrument
    WireEnrollment:
      type: object
      properties:
        id:
          type: string
          format: uuid
        challengeId:
          type: string
          format: uuid
        challengeName:
          type: string
        stage:
          type: integer
        accountNumber:
          type: string
        type:
          type: string
          enum:
            - trial
            - standard
            - funded
        status:
          type: string
          enum:
            - registered
            - in_progress
            - passed
            - failed
            - reset
            - cancelled
            - upgraded
            - finished
        startingBalance:
          type: integer
          description: Whole dollars.
        ddMode:
          type: string
          enum:
            - static_balance
            - static_equity
            - trailing_max_equity_eod
            - trailing_max_equity_intraday
        startsAt:
          type:
            - number
            - 'null'
          description: Epoch seconds; set at the first fill, not at enrollment.
        endsAt:
          type:
            - number
            - 'null'
          description: Epoch seconds.
        failReason:
          type:
            - string
            - 'null'
        createdAt:
          type: number
          description: Epoch seconds.
        progress:
          $ref: '#/components/schemas/WireEnrollmentProgress'
      required:
        - id
        - challengeId
        - challengeName
        - stage
        - accountNumber
        - type
        - status
        - startingBalance
        - ddMode
        - createdAt
        - progress
    WireEnrollmentProgress:
      type:
        - object
        - 'null'
      properties:
        equity:
          type:
            - number
            - 'null'
        balance:
          type:
            - number
            - 'null'
        dayAnchorEquity:
          type:
            - number
            - 'null'
          description: The day-roll anchor level driving the daily floor.
        hwmEquity:
          type:
            - number
            - 'null'
          description: Lifetime high-water equity, driving the trailing total floor.
        dailyFloor:
          type:
            - number
            - 'null'
          description: Absolute equity level. A breach fires when equity crosses below.
        totalFloor:
          type:
            - number
            - 'null'
          description: Absolute equity level. A breach fires when equity crosses below.
        profitTargetLevel:
          type: number
        tradingDays:
          type: integer
          description: Distinct session days with at least one fill.
        minTradingDays:
          type: integer
        openPositions:
          type: integer
      required:
        - equity
        - balance
        - profitTargetLevel
        - tradingDays
        - minTradingDays
        - openPositions
  securitySchemes:
    sessionCookie:
      type: apiKey
      in: cookie
      name: session
      description: >-
        The signed session cookie of a logged-in trdrs user. First-party/browser
        only; a firm API key cannot reach a route secured this way.

````