---
title: "Submit Position Instructions"
method: POST
path: "/v1/accounts/{account_id}/positions/instructions"
tags: ["Positions"]
---

# Submit Position Instructions

`POST /v1/accounts/{account_id}/positions/instructions`

## Request

- Base URL: `https://api.clearstreet.com`
- URL: `https://api.clearstreet.com/v1/accounts/{account_id}/positions/instructions`
- Auth: HTTP bearer

Submit one or more position instructions (Exercise, Do-Not-Exercise,
Contrary Exercise Advice) against the account.

Batch semantics:
- **All rows accepted** → `200 OK`. Every row is in `data` with
  `status = SENT`.
- **Partial success** → `207 Multi-Status`. `data` contains every
  row; rejected rows carry `status = REJECTED` and
  `rejection_reason`. The top-level `error` summarizes the batch
  failure.
- **All rows rejected** → `4xx`/`5xx`. The HTTP status reflects
  the aggregate cause: `409` when every row was a duplicate, `400`
  for validation failures like DNE/CEA on a non-expiry day, `503`
  if the clearing service is unavailable. `data` still contains
  every row carrying `status = REJECTED` and `rejection_reason`
  so callers can attribute failures by `client_instruction_id`; the
  top-level `error` summarizes the batch.

## Path parameters

- `account_id` integer, required

## Request body

- PositionInstructionSubmissionRequest[]
  - `client_instruction_id` string, nullable: Caller-supplied idempotency key. Echoed on the response. The server generates a unique id when omitted.
  - `instruction_type` 'EXERCISE' | 'DO_NOT_EXERCISE' | 'CONTRARY_EXERCISE', required: The action to take against an options position.
  - `instrument_id` string, uuid, required: Identifier of the options contract to act on. Unknown ids return 404.
  - `quantity` string, required: Number of contracts to include in the instruction.

## Response `200`

All instructions accepted

- object
  - `error` ApiError: A direct mapping of tonic::Status, for use in HTTP responses.
    - `code` integer, required: The error code is used to identify the nature of the error. It corresponds to an HTTP status code.
    - `details` object[]
    - `message` string, required: A human-readable message providing more details about the error.
  - `metadata` ResponseMetadata, required: Metadata for the response. This will always contain a request ID which can be used to identify the request to Clear Street for tracing, and optionally may include pagination data.
    - `next_page_token` string, byte, nullable: Base64URL-encoded pagination token
    - `page_number` integer, nullable: Pagination. Included if this was a GET (list) response
    - `previous_page_token` string, byte, nullable: Base64URL-encoded pagination token
    - `request_id` string, required: A unique ID for this request, generated upon ingestion of the request.
    - `total_items` integer, nullable: Total number of items available (not just in this page).
    - `total_pages` integer, nullable: Total number of pages available.
  - `data` PositionInstruction[], required
    - `accepted_quantity` string, nullable: Number of contracts accepted by the clearing venue. Populated once the instruction reaches `ACCEPTED`. When a null/undefined value is observed, it indicates that there is no available data.
    - `account_id` integer, required
    - `client_instruction_id` string, required: Caller-supplied idempotency key echoed from the submit request; the server-assigned fallback when none was supplied.
    - `created_at` string, date-time, nullable: When the instruction was first accepted by the service. When a null/undefined value is observed, it indicates that there is no available data.
    - `id` string, uuid, required: Server-assigned id. Used as the path parameter on cancel.
    - `instruction_type` 'EXERCISE' | 'DO_NOT_EXERCISE' | 'CONTRARY_EXERCISE', required: The action to take against an options position.
    - `instrument_id` string, uuid, required: Identifier of the options contract this instruction acts on.
    - `quantity` string, required: Number of contracts included in the instruction.
    - `rejection` PositionInstructionRejection: Machine-readable detail for a rejected position instruction. Present on every rejected row, across the full lifecycle — submit, cancel, get, and list. Branch on `reason` for programmatic handling and template your own copy from `metadata`, or show `description` directly.
      - `description` string, required: Human-readable explanation of the rejection. Duplicates the top-level `rejection_reason`; prefer this field.
      - `domain` string, required: Namespacing domain of the `reason` code — `com.clearstreet.oems.exercise` for reasons OEMS validates, `com.clearstreet.oems.clearing` for clearing-owned reasons.
      - `metadata` object, required: Reason-specific parameters as a string→string map. Which keys are present depends on `reason`: - `INSUFFICIENT_POSITION` → `available`, `requested` - `DNE_NOT_ON_EXPIRY` / `CEA_NOT_ON_EXPIRY` → `expiry`, `business_date` - `EXERCISE_PAST_CUTOFF` → `cutoff_time` - `DUPLICATE_INSTRUCTION` → `existing_id` Empty for reasons that carry no parameters. New keys may be added over time, so treat unknown keys leniently.
      - `reason` string, required: Stable, machine-readable reason code, e.g. `DNE_NOT_ON_EXPIRY`, `INSUFFICIENT_POSITION`, `OPTIONS_LEVEL_EXCEEDED`, `EXERCISE_PAST_CUTOFF`.
    - `rejection_reason` string, nullable: Human-readable explanation populated on any non-success terminal status — `REJECTED` or `CANCEL_FAILED`. On a `207 Multi-Status` batch submit the top-level `error` field summarizes the batch; per-row detail continues to live here. When a null/undefined value is observed, it indicates it does not apply.
    - `status` 'SENT' | 'ACCEPTED' | 'REJECTED' | 'CANCEL_REQUESTED' | 'CANCELLED' | 'CANCEL_FAILED' | 'UNKNOWN', required: Lifecycle status of a position instruction. - `SENT`: accepted and submitted to the clearing venue. - `ACCEPTED`: terminal — accepted by the clearing venue. - `REJECTED`: terminal rejection; `rejection_reason` carries the detail. Covers both venue-reported rejections and rejections raised before the instruction reached the clearing venue (e.g. duplicate `client_instruction_id`, `DO_NOT_EXERCISE` / `CONTRARY_EXERCISE` submitted on a non-expiry day, insufficient position, or an instrument that does not resolve). - `CANCEL_REQUESTED`: cancel accepted; final cancel state pending. - `CANCELLED`: terminal — cancel completed. - `CANCEL_FAILED`: cancel could not be completed; operator attention required. `rejection_reason` carries the detail. - `UNKNOWN`: status could not be determined.
    - `symbol` string, required: Options symbol (OSI) for display.
    - `underlying_instrument_id` string, uuid, nullable: Identifier of the underlying instrument, when available. When a null/undefined value is observed, it indicates it does not apply.
    - `updated_at` string, date-time, nullable: When the instruction's lifecycle state last changed. When a null/undefined value is observed, it indicates that there is no available data.

## Other responses

- `207`: Partial success — some rows accepted, others rejected
- `400`: Invalid request or all rows rejected by validation
- `403`: Forbidden
- `404`: Account or instrument not found
- `409`: All rows rejected as duplicates
- `500`: All rows rejected by an internal server fault
- `503`: All rows rejected because the clearing service was unavailable

## Changes

- **2026-10-16** `1bd9eddeffc8`: 6 breaking, 1 warning, 19 info
  - removed the required property `allOf[subschema #2]/data/items/instruction_id` from the response with the `200` status
  - removed the required property `allOf[subschema #2]/data/items/instruction_id` from the response with the `207` status
  - removed the required property `allOf[subschema #2]/data/items/instruction_id` from the response with the `400` status
  - removed the required property `allOf[subschema #2]/data/items/instruction_id` from the response with the `409` status
  - …22 more
- **2026-06-10** `99644beba9d7`: 6 info
  - removed the `ENGINE_REJECTED` enum value from the `allOf[subschema #2]/data/items/status` response property for the response status `200`
  - removed the `ENGINE_REJECTED` enum value from the `allOf[subschema #2]/data/items/status` response property for the response status `207`
  - removed the `ENGINE_REJECTED` enum value from the `allOf[subschema #2]/data/items/status` response property for the response status `400`
  - removed the `ENGINE_REJECTED` enum value from the `allOf[subschema #2]/data/items/status` response property for the response status `409`
  - …2 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/clear-street/apis/clear-street-trading-api/changes/v1/accounts/:account_id/positions/instructions/post.md)

---

[API](https://skmtc.dev/clear-street/apis/clear-street-trading-api.md) - [All operations](https://skmtc.dev/clear-street/apis/clear-street-trading-api/llms.txt) - [OpenAPI document](https://skmtc.dev/clear-street/apis/clear-street-trading-api/revisions/52e77ea7d731?raw)
