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

# Open Positions

> Returns your open positions, aggregated per side (one line each for buy and sell). Each line shows entry and mark price, gross P&L (price only), accrued carry, net P&L (price plus carry), the fee to close, and net margin - what you'd reclaim if you closed now.



## OpenAPI

````yaml /api-reference/openapi.json get /positions
openapi: 3.1.0
info:
  title: Marks Partner API
  version: v2
  description: >
    Marks is an FX hedging platform. This API lets you open and manage hedges
    programmatically, currently on USDT/NGN, with more pairs to follow.


    Each hedge is a non-deliverable forward (NDF): a contract that fixes an
    exchange rate for a chosen tenor and cash-settles the difference at
    maturity, with no physical delivery of currency. A hedge opens at the
    prevailing spot rate, accrues carry over its tenor, and settles in USDC.


    The API is organized around four areas:


    - **Market data** - available markets, prices, capacity, and the current
    carry rate.

    - **Account** - your balance, margin, exposure, and unrealized P&L.

    - **Quotes** - an indicative price and cost breakdown for a hedge before you
    open it.

    - **Hedges** - open, monitor, close, and review hedges.


    Every response uses the same envelope: `{ "data", "error", "meta" }`. On
    success `data` is populated and `error` is null; on failure `data` is null
    and `error` carries a machine-readable `code`, a `message`, and optional
    `details`. Amounts are in USDC unless noted.
servers:
  - url: https://api.marks.finance/api/v2/partners
    description: Base URL (mode is selected by the API key prefix / X-Marks-Mode header)
security:
  - ApiKey: []
tags:
  - name: Authentication
    description: >
      Every request authenticates with your API key, sent as a Bearer token:


      ```

      Authorization: Bearer mk_live_xxxxxxxx

      ```


      Create and manage keys in Settings. The full key is shown only once at
      creation and cannot be retrieved later, so save it somewhere secure and
      keep it secret. A request without a valid key returns `401`.


      Your key prefix selects the environment:


      - `mk_live_` - production

      - `mk_test_` - sandbox


      The prefix is authoritative: a `mk_test_` key always runs against the
      sandbox, so a test call can never reach production by accident. The same
      endpoints serve both; only the key differs.
  - name: Sandbox
    description: >
      The sandbox is a full copy of the API running against test infrastructure,
      so code that works in the sandbox works in production unchanged. Use it to
      build and verify your integration before going live.


      Create a `mk_test_` key in Settings and send it as your Bearer token.
      Sandbox accounts are funded with test balances, so you can open and settle
      hedges end to end without real money.


      Sandbox and production are fully isolated, with separate balances,
      positions, and history. A test key cannot see or touch production data.


      Prices in the sandbox track the same live FX rates as production. Fees in
      the sandbox are indicative and may differ from production.


      In the reference below, **Test Request** calls the API live with the key
      you provide. With a `mk_test_` key this is safe to experiment with freely.
      With a `mk_live_` key the calls are real, and opening a hedge places a
      real position.
  - name: Errors
    description: >
      Every error response has `data: null` and a populated `error` with a
      stable `code`, a human-readable `message`, and optional `details`. Branch
      on `code`.


      | Code | HTTP | Meaning |

      |---|---|---|

      | `validation_error` | 400 | Malformed or missing fields (see
      `details.fields`) |

      | `market_not_allowed` | 400 | Market not enabled for your account |

      | `exposure_exceeded` | 400 | Total open exposure would exceed your cap
      (see `details.available_headroom_usd`) |

      | `insufficient_collateral` | 400 | Not enough balance for the requested
      size |

      | `hedge_not_open` | 400 | The target hedge is not open, so it can't be
      added to |

      | `account_not_configured` | 400 | Your partner account has no on-chain
      account set yet |

      | `missing_credentials` | 401 | No `Authorization` header |

      | `invalid_api_key` | 401 | API key not found or revoked |

      | `insufficient_scope` | 403 | API key lacks the required scope |

      | `account_forbidden` | 403 | The requested account is not yours |

      | `hedge_not_found` | 404 | No hedge with that id on your account |

      | `no_open_hedge` | 404 | No open hedge on that market + side to add to
      (open one instead) |

      | `hedge_exists` | 409 | You already have an open hedge on that market +
      side; add to it or settle it first |

      | `idempotency_in_flight` | 409 | A request with this `Idempotency-Key` is
      still processing |

      | `idempotency_key_reuse` | 409 | `Idempotency-Key` reused with a
      different request body |

      | `rate_limited` | 429 | Too many requests |

      | `quote_failed` | 502 | Could not build a quote |

      | `execution_failed` | 502 | The order could not be submitted |

      | `onchain_read_failed` | 502 | Could not read market or account data |

      | `price_unavailable` | 503 | Price feed temporarily unavailable |

      | `executor_unavailable` | 503 | Execution service temporarily unavailable
      |

      | `service_unavailable` | 503 | A required service is temporarily
      unavailable |


      5xx errors are transient; retry with backoff.
  - name: Market data
    description: >
      Read-only market data to size and price hedges before opening them.


      - `GET /markets` lists the markets available to you, with each market's
      status, current rate, available capacity per side, and daily carry rate.

      - `GET /prices` returns the latest mid rate for a market.


      Prices here are indicative mid rates for reference. The executable price
      for a hedge, with impact applied, comes from a quote.
  - name: Account
    description: >
      Your account: balances, margin, exposure, and open positions.


      - `GET /account` returns a summary - free balance, margin in use, total
      exposure, and unrealized P&L.

      - `GET /positions` returns each open position with its entry, mark price,
      gross and net P&L, accrued carry, and net margin.


      Amounts are in USDC.
  - name: Quotes
    description: >-
      Price a hedge before you open it. Quotes are indicative: they are not
      binding and not persisted, and opening a hedge re-prices against the live
      rate.
  - name: Hedges
    description: >
      Open, close, list, and review hedges.


      ## Lifecycle


      Opening and closing are asynchronous: you submit an order and it's filled
      shortly after, so you poll for the result. There are no webhooks yet.


      1. **Quote** (optional) - `POST /quotes` returns an indicative price and
      full cost breakdown. Quotes are not binding and not persisted; opening
      re-prices against the live rate.

      2. **Open** - `POST /hedges` returns `status: "submitted"` with an
      `order_tx_hash` and a `hedge_id`. The position is not live yet.

      3. **Fill** - poll `GET /hedges/{id}` until `status` is `filled` (with a
      `fill_tx_hash`). This usually takes a few seconds.

      4. **Monitor** - `GET /positions` shows the live position (mark price,
      gross and net P&L, accrued carry). `GET /account` shows aggregate balance,
      margin, exposure, and unrealized P&L.

      5. **Close** - `POST /hedges/close` closes a (market, side); it fills the
      same asynchronous way, and `GET /positions` returns to flat once drained.

      6. **Review** - `GET /hedges/history` lists closed hedges with realized
      P&L, carry, and fees.


      Each hedge carries a `maturity_at`, its settlement date derived from the
      tenor. Status values: `submitting`, `submitted`, `filled`, `failed`,
      `closed`.


      **One open hedge per market + side.** You hold at most one open hedge on a
      given market and side. Opening a second on the same market+side returns
      `409 hedge_exists`. To grow a position, add to the existing hedge with
      `POST /hedges/{id}/add` (or `POST /hedges/add` by market + side): the
      added notional nets into the same position at a size-weighted blended rate
      and inherits the original `maturity_at`. To change the maturity, settle
      the current hedge and open a new one.


      ## Idempotency


      Opening and closing are state-changing, so make them safe to retry with an
      `Idempotency-Key` header (any unique string, such as a UUID or your own
      deal id):


      ```

      Idempotency-Key: 9f1c2e7a-...

      ```


      Retrying with the same key and the same body returns the original result
      instead of acting twice. Reusing a key with a different body returns `409
      idempotency_key_reuse`. A key whose request is still in flight returns
      `409 idempotency_in_flight`. Keys are scoped per environment, so sandbox
      and production never collide.
paths:
  /positions:
    get:
      tags:
        - Account
      summary: Open Positions
      description: >-
        Returns your open positions, aggregated per side (one line each for buy
        and sell). Each line shows entry and mark price, gross P&L (price only),
        accrued carry, net P&L (price plus carry), the fee to close, and net
        margin - what you'd reclaim if you closed now.
      operationId: get_positions_api_v2_partners_positions_get
      parameters: []
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope_List_Position__'
              example:
                data:
                  - market: USDTNGN
                    side: sell
                    size_usd: 100000
                    collateral_usdc: 5000
                    entry_price: 1619.8
                    mark_price: 1622
                    gross_pnl_usd: -135.9
                    accrued_carry_usd: 100
                    net_pnl_usd: -35.9
                    closing_fee_usd: 40
                    net_margin_usd: 4924.1
                    maturity_at: '2026-08-15T00:00:00Z'
                error: null
                meta:
                  source: onchain
        '401':
          description: missing_credentials, invalid_api_key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: insufficient_scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: rate_limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: onchain_read_failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    Envelope_List_Position__:
      properties:
        data:
          anyOf:
            - items:
                $ref: '#/components/schemas/Position'
              type: array
            - type: 'null'
          title: Data
        error:
          anyOf:
            - $ref: '#/components/schemas/ErrorObject'
            - type: 'null'
        meta:
          additionalProperties: true
          type: object
          title: Meta
      type: object
      title: Envelope[List[Position]]
    ErrorResponse:
      type: object
      properties:
        data:
          type: 'null'
        error:
          $ref: '#/components/schemas/ErrorObject'
        meta:
          type: object
      required:
        - data
        - error
        - meta
    Position:
      properties:
        market:
          type: string
          title: Market
        side:
          type: string
          title: Side
          description: buy (long) or sell (short).
        size_usd:
          type: number
          title: Size Usd
          description: Position notional.
        collateral_usdc:
          type: number
          title: Collateral Usdc
          description: Margin posted.
        entry_price:
          type: number
          title: Entry Price
        mark_price:
          type: number
          title: Mark Price
          description: Current price.
        gross_pnl_usd:
          type: number
          title: Gross Pnl Usd
          description: Price P&L, before carry (mark-to-market).
        accrued_carry_usd:
          type: number
          title: Accrued Carry Usd
          description: Carry accrued since open, signed (+ earned / − paid).
        net_pnl_usd:
          type: number
          title: Net Pnl Usd
          description: Net of carry = gross P&L + accrued carry.
        closing_fee_usd:
          type: number
          title: Closing Fee Usd
          description: Platform fee to exit the full size.
        net_margin_usd:
          type: number
          title: Net Margin Usd
          description: Reclaimable if closed now = margin + net P&L − closing fee.
        maturity_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Maturity At
          description: Settlement date (ISO-8601).
      type: object
      required:
        - market
        - side
        - size_usd
        - collateral_usdc
        - entry_price
        - mark_price
        - gross_pnl_usd
        - accrued_carry_usd
        - net_pnl_usd
        - closing_fee_usd
        - net_margin_usd
      title: Position
    ErrorObject:
      properties:
        code:
          type: string
          title: Code
          description: Machine-readable error code, e.g. exposure_exceeded.
        message:
          type: string
          title: Message
          description: Human-readable explanation.
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
          description: Optional structured context (e.g. field errors, limits).
      type: object
      required:
        - code
        - message
      title: ErrorObject
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer
      description: 'Partner API key: `mk_live_...` (production) or `mk_test_...` (sandbox).'

````