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

# API Conventions

> Base URL, response envelope, amounts, idempotency, rate limits, and error codes shared across every endpoint.

Everything in the API follows a small set of shared conventions. Read this once and the rest of the reference reads consistently.

## Base URL

All endpoints are served over HTTPS and share one base:

```text theme={null}
https://api.marks.finance/api/v2/partners
```

Plain HTTP is not supported.

## Authentication

Every request carries your API key as a Bearer token. The key prefix selects the environment: `mk_live_` for production, `mk_test_` for sandbox. The same endpoints serve both. See [Authentication](/guides/authentication) for the full details.

```text theme={null}
Authorization: Bearer mk_live_xxxxxxxx
```

## Response envelope

Every endpoint returns the same envelope:

```json theme={null}
{ "data": ..., "error": null, "meta": {} }
```

On success `data` is populated and `error` is null. On failure `data` is null and `error` carries a machine-readable `code`, a human-readable `message`, and optional `details`. `meta` carries request context such as the data source. Branch on `error.code`, not on the message text.

## Amounts and rates

Monetary amounts are in **USDC** unless a field name says otherwise (fields ending in `_usd` or `_usdc`). Exchange rates are decimal numbers in quote currency per USDT - a `price` of `1620.5` on `USDTNGN` means 1,620.5 naira per USDT. Timestamps are ISO-8601 in UTC.

## Asynchronous actions

Opening, adding to, reducing, and closing a Hedge are asynchronous. The call returns `status: "submitted"` with a transaction hash, and the position settles on-chain shortly after. You poll `GET /hedges/{id}` (or `GET /positions`) for the result. There are no webhooks yet.

## Idempotency

Opening, adding, reducing, 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):

```text theme={null}
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.

## Rate limits

Requests are rate limited per API key. If you exceed the limit you get `429 rate_limited`; back off and retry. Read endpoints (markets, prices, account, positions) are safe to poll at a steady cadence; there's no need to poll faster than every second or two.

## Errors

Every error response has `data: null` and a populated `error` with a stable `code`, a human-readable `message`, and optional `details`. Branch on `code`. 4xx codes are your request to fix; 5xx codes are transient, so retry with backoff.

```json theme={null}
{
  "data": null,
  "error": {
    "code": "exposure_exceeded",
    "message": "Total open exposure would exceed your cap.",
    "details": { "available_headroom_usd": 12000 }
  },
  "meta": {}
}
```

### Error codes

| 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 and side to add to (open one instead)                   |
| `hedge_exists`            | 409  | You already have an open Hedge on that market and 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                                        |
