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

# Add to a Hedge

> Increases your existing open hedge on a market+side by adding notional, **keeping the same maturity** - the convenience form for the desk, which knows the market and side but not the hedge id. Resolves the open hedge server-side. Returns `404 no_open_hedge` if you don't have one on that side (open one instead). Pass an `Idempotency-Key` to make retries safe.



## OpenAPI

````yaml /api-reference/openapi.json post /hedges/add
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:
  /hedges/add:
    post:
      tags:
        - Hedges
      summary: Add to a Hedge
      description: >-
        Increases your existing open hedge on a market+side by adding notional,
        **keeping the same maturity** - the convenience form for the desk, which
        knows the market and side but not the hedge id. Resolves the open hedge
        server-side. Returns `404 no_open_hedge` if you don't have one on that
        side (open one instead). Pass an `Idempotency-Key` to make retries safe.
      operationId: add_to_hedge_by_side_api_v2_partners_hedges_add_post
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddBySideRequest'
            example:
              market: USDTNGN
              side: sell
              additional_notional_usd: 50000
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope_HedgeAddResult_'
              example:
                data:
                  status: submitted
                  order_tx_hash: >-
                    0x9c1e4f2a7b8d3e6c5a0f1b2d4e6a8c0f2b4d6e8a1c3f5b7d9e0a2c4f6b8d0e2a
                  hedge_id: hdg_3f9a2c7e5b1d
                  market: USDTNGN
                  side: sell
                  additional_notional_usd: 50000
                  collateral_usdc: 2540
                  new_notional_usd: 150000
                  maturity_at: '2026-08-15T00:00:00Z'
                error: null
                meta: {}
        '400':
          description: >-
            validation_error, market_not_allowed, exposure_exceeded,
            insufficient_collateral, account_not_configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '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'
        '404':
          description: no_open_hedge
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: idempotency_in_flight, idempotency_key_reuse
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: rate_limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: execution_failed, quote_failed, onchain_read_failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: price_unavailable, executor_unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    AddBySideRequest:
      properties:
        market:
          type: string
          title: Market
          description: e.g. USDTNGN
          default: USDTNGN
        side:
          type: string
          title: Side
          description: buy | sell — the side of the open hedge to add to
        additional_notional_usd:
          type: number
          exclusiveMinimum: 0
          title: Additional Notional Usd
          description: Notional to add to the existing hedge.
      type: object
      required:
        - side
        - additional_notional_usd
      title: AddBySideRequest
    Envelope_HedgeAddResult_:
      properties:
        data:
          anyOf:
            - $ref: '#/components/schemas/HedgeAddResult'
            - type: 'null'
        error:
          anyOf:
            - $ref: '#/components/schemas/ErrorObject'
            - type: 'null'
        meta:
          additionalProperties: true
          type: object
          title: Meta
      type: object
      title: Envelope[HedgeAddResult]
    ErrorResponse:
      type: object
      properties:
        data:
          type: 'null'
        error:
          $ref: '#/components/schemas/ErrorObject'
        meta:
          type: object
      required:
        - data
        - error
        - meta
    HedgeAddResult:
      properties:
        status:
          type: string
          title: Status
          description: >-
            `submitted` - the top-up is filled shortly after; poll GET
            /hedges/{id}.
        order_tx_hash:
          anyOf:
            - type: string
            - type: 'null'
          title: Order Tx Hash
          description: The increase-order transaction. The fill lands later.
        hedge_id:
          type: string
          title: Hedge Id
          description: The hedge that was increased (unchanged - the top-up nets into it).
        market:
          type: string
          title: Market
        side:
          type: string
          title: Side
          description: buy (long) or sell (short).
        additional_notional_usd:
          type: number
          title: Additional Notional Usd
          description: Notional added by this top-up.
        collateral_usdc:
          type: number
          title: Collateral Usdc
          description: Extra locked for the added notional (margin + open fee).
        new_notional_usd:
          anyOf:
            - type: number
            - type: 'null'
          title: New Notional Usd
          description: >-
            The hedge's total notional after the add (null if the stored total
            couldn't be read back).
        maturity_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Maturity At
          description: >-
            Settlement date (ISO-8601), unchanged - the top-up inherits the
            original maturity.
      type: object
      required:
        - status
        - hedge_id
        - market
        - side
        - additional_notional_usd
        - collateral_usdc
      title: HedgeAddResult
    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).'

````