> For the complete documentation index, see [llms.txt](https://docs.dimes.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dimes.fi/for-developers/api-and-events/api-reference.md).

# API Reference

**Base URLs:**

| Environment | Base URL                          | API key prefix     |
| ----------- | --------------------------------- | ------------------ |
| Production  | `https://api.dimes.fi/v1`         | `dm_live_skey_...` |
| Sandbox     | `https://api-sandbox.dimes.fi/v1` | `dm_sbx_skey_...`  |

Pick one environment per integration. Keys and URLs are not interchangeable across environments — see [Environments](/for-developers/getting-started/environments.md) for the full comparison.

**OpenAPI spec:**

* Interactive Swagger UI: [`https://api.dimes.fi/v1/customer-docs`](https://api.dimes.fi/v1/customer-docs) (production) or [`https://api-sandbox.dimes.fi/v1/customer-docs`](https://api-sandbox.dimes.fi/v1/customer-docs) (sandbox)
* Raw JSON: [`https://api.dimes.fi/v1/customer-docs-json`](https://api.dimes.fi/v1/customer-docs-json) (production) or [`https://api-sandbox.dimes.fi/v1/customer-docs-json`](https://api-sandbox.dimes.fi/v1/customer-docs-json) (sandbox)

***

## Conventions

| Convention          | Choice                                             |
| ------------------- | -------------------------------------------------- |
| **Field casing**    | `snake_case`                                       |
| **URL path casing** | `kebab-case`                                       |
| **Pagination**      | Cursor-based                                       |
| **List envelope**   | `{ "data": [...], "has_more": bool }`              |
| **Error format**    | `{ "error": { "type", "code", "message" } }`       |
| **Monetary values** | Pips (string) + dollar (string)                    |
| **IDs**             | Prefixed strings (`dm_pos_`, `dm_off_`, `dm_mkt_`) |

### Monetary values

Every monetary field appears twice — as precise internal units (pips, string) and as a human-readable dollar amount ( string):

```json
{
  "entry_price_usd_pips": "6500",
  "entry_price_usd": "0.65",
  "collateral_usd_pips": "500000",
  "collateral_usd": "50.00"
}
```

The `_usd_pips` fields are the source of truth (10,000 pips = $1.00). The `_usd` fields are convenience values for display.

### Pagination

All list endpoints use cursor-based pagination:

| Param            | Type    | Default | Description                                  |
| ---------------- | ------- | ------- | -------------------------------------------- |
| `limit`          | integer | 25      | Results per page (1–100)                     |
| `starting_after` | string  | —       | Cursor: return results after this object ID  |
| `ending_before`  | string  | —       | Cursor: return results before this object ID |

Response envelope:

```json
{
  "data": [
    ...
  ],
  "has_more": true
}
```

`starting_after` and `ending_before` are mutually exclusive.

### Expanding sub-resources

Some endpoints accept an `expand` query parameter to inline related sub-resources in the response, saving a follow-up request per item. The value is a comma-separated list of allowed expansion keys, documented per endpoint.

```
GET /prediction-markets/positions?expand=unwinds
GET /prediction-markets/positions?expand=unwinds,foo,bar
```

Each expanded sub-resource appears as a top-level field on the parent object using the same shape it would have if fetched standalone. When the parent has no data for the requested sub-resource, the field is omitted.

### SDK method mapping

If you're using `@dimes-dot-fi/sdk`, each endpoint maps to a client method:

| Endpoint                            | SDK method                                    |
| ----------------------------------- | --------------------------------------------- |
| `GET /markets`                      | `client.getMarkets(params?)`                  |
| `GET /markets/:ticker`              | `client.getMarket(ticker)`                    |
| `GET /contract-info`                | `client.getContractInfo()`                    |
| `POST /tokens`                      | Handled by `ApiKeyAuth` automatically         |
| `POST /draft-quotes`                | `client.createDraftQuote(params)`             |
| `POST /promoted-quotes/:id`         | `client.promoteDraftQuote(draftId)`           |
| `POST /quotes`                      | `client.createQuote(params)`                  |
| `GET /positions`                    | `client.getPositions(params?)`                |
| `GET /positions/:id/transactions`   | `client.getPositionTransactions(positionId)`  |
| `GET /positions/:id/partial-closes` | `client.getPositionPartialCloses(positionId)` |
| `GET /user-limits`                  | `client.getUserLimits()`                      |
| `GET /partner-limits`               | `client.getPartnerLimits()`                   |
| `GET /fee-rates`                    | `client.getFeeRates(params?)`                 |
| `POST /fee-reports`                 | `client.getFeeReport(params)`                 |

The high-level `executeQuote()` function handles the full draft → promote flow with auto-retry and correction; `useQuote` / `useQuoteMachine` wrap it for React. See [SDK Installation](/for-developers/getting-started/sdk-installation.md) and [React Hooks](/for-developers/getting-started/react-hooks.md).

***

## 1. Markets

### List markets

Returns markets currently eligible for trading.

```
GET /prediction-markets/markets
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const markets = await client.getMarkets({ limit: 25, sort: "depth_desc", expand: ["prices"] });
// markets.data: Market[]   markets.hasMore: boolean   markets.totalCount?: number
```

**Auth:** User JWT or partner API key

**Query parameters:**

| Param                     | Type    | Default      | Description                                                                                                                                   |
| ------------------------- | ------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `query`                   | string  | —            | Free-text search term. When set, results are filtered to markets matching the term (see Search behavior below).                               |
| `accepting_new_positions` | boolean | —            | Filter on whether **either** side is accepting new positions. `true` returns markets where YES or NO accepts.                                 |
| `limit`                   | integer | 25           | Max results (1–100)                                                                                                                           |
| `starting_after`          | string  | —            | Cursor: return results after this ticker                                                                                                      |
| `ending_before`           | string  | —            | Cursor: return results before this ticker                                                                                                     |
| `category`                | string  | —            | Filter by category                                                                                                                            |
| `provider`                | string  | —            | Filter: `polymarket`                                                                                                                          |
| `status`                  | string  | `active`     | Filter: `active`, `closed`, `determined`, `finalized`, `disputed`                                                                             |
| `sort`                    | string  | `ticker_asc` | Sort order: `ticker_asc` (alphabetical), `depth_desc` (deepest markets first), `discovered_at_desc` (newest markets first by discovery date). |
| `expand`                  | string  | —            | Comma-separated list of sub-resources to embed inline. Allowed values: `total_count`, `prices`.                                               |

**Search behavior:**

Pass `query` to search. It matches against multiple fields:

| Field        | Match type                       |
| ------------ | -------------------------------- |
| Market title | Case-insensitive substring match |
| Ticker       | Case-insensitive exact match     |
| Yes token ID | Exact match                      |
| No token ID  | Exact match                      |

```typescript
const results = await client.getMarkets({ query: "bitcoin", limit: 10 });
```

**Response: `200 OK`**

```json
{
  "data": [
    {
      "accepting_new_positions": true,
      "id": "dm_mkt_abc123",
      "ticker": "will-btc-hit-100k-2025",
      "polymarket": {
        "slug": "will-btc-hit-100k-2025",
        "condition_id": "0xabc123def4567890abc123def4567890abc123def4567890abc123def4567890",
        "yes_token_id": "21742633143463906290569050155826241533067272736897614950488156847949938836455",
        "no_token_id": "71321045679252212594626385532706912750332728571942532289631379312455583992563"
      },
      "title": "Will BTC hit $100K?",
      "yes_sub_title": "Yes, before September 30",
      "category": "crypto",
      "rejection_reason_code": null,
      "sided_eligibility": {
        "yes": {
          "accepting_new_positions": true,
          "rejection_reason_code": null
        },
        "no": {
          "accepting_new_positions": false,
          "rejection_reason_code": "QUOTE_SIDE_CAPACITY_EXCEEDED"
        }
      },
      "status": "open",
      "tags": [
        "crypto",
        "bitcoin"
      ],
      "close_time": "2025-09-30T00:00:00.000Z",
      "discovered_at": "2025-09-01T08:00:00.000Z",
      "latest_enter_at": "2025-09-29T23:00:00.000Z",
      "provider": "polymarket",
      "min_collateral_usd_pips": "200000",
      "min_collateral_usd": "0.02",
      "min_notional_usd_pips": "10000",
      "min_notional_usd": "1.00",
      "leverage": {
        "min_bps": 20000,
        "max_yes_bps": 100000,
        "max_no_bps": 100000,
        "step_bps": 2500,
        "max_market_leverage_per_notional": {
          "yes": {
            "at100_usd_bps": 100000,
            "at500_usd_bps": 80000,
            "at1000_usd_bps": 60000,
            "at10000_usd_bps": 30000
          },
          "no": {
            "at100_usd_bps": 100000,
            "at500_usd_bps": 80000,
            "at1000_usd_bps": 60000,
            "at10000_usd_bps": 30000
          }
        }
      },
      "fees": {
        "origination_tiers": [
          {
            "max_leverage_bps": 40000,
            "fee_bps": 100
          },
          {
            "max_leverage_bps": 70000,
            "fee_bps": 125
          },
          {
            "max_leverage_bps": 100000,
            "fee_bps": 150
          }
        ],
        "lifetime_fee_apr_bps": 2000,
        "liquidation_fee_bps": 1000
      },
      "max_notional_yes_usd_pips": "500000000",
      "max_notional_yes_usd": "50000.00",
      "max_notional_no_usd_pips": "500000000",
      "max_notional_no_usd": "50000.00",
      "capacity_max_notional_yes_usd_pips": "400000000",
      "capacity_max_notional_yes_usd": "40000.00",
      "capacity_max_notional_no_usd_pips": "400000000",
      "capacity_max_notional_no_usd": "40000.00",
      "slippage_max_notional_yes_usd_pips": "350000000",
      "slippage_max_notional_yes_usd": "35000.00",
      "slippage_max_notional_no_usd_pips": "350000000",
      "slippage_max_notional_no_usd": "35000.00",
      "prices": {
        "yes_ask_price_usd": "0.51",
        "yes_ask_price_usd_pips": "5100",
        "yes_bid_price_usd": "0.49",
        "yes_bid_price_usd_pips": "4900",
        "no_ask_price_usd": "0.51",
        "no_ask_price_usd_pips": "5100",
        "no_bid_price_usd": "0.49",
        "no_bid_price_usd_pips": "4900"
      }
    }
  ],
  "has_more": true
}
```

**Field reference:**

| Field                                                                               | Type                      | Description                                                                                                                                                                                                                                                    |
| ----------------------------------------------------------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accepting_new_positions`                                                           | boolean                   | Whether this market is currently accepting new positions on **either** side. See `sided_eligibility` for per-side breakdown.                                                                                                                                   |
| `capacity_max_notional_no_usd`                                                      | string or null            | Capacity-limited maximum notional for NO side (dollar display)                                                                                                                                                                                                 |
| `capacity_max_notional_no_usd_pips`                                                 | string or null            | Capacity-limited maximum notional for NO side (internal precision); `null` if capacity unknown                                                                                                                                                                 |
| `capacity_max_notional_yes_usd`                                                     | string or null            | Capacity-limited maximum notional for YES side (dollar display)                                                                                                                                                                                                |
| `capacity_max_notional_yes_usd_pips`                                                | string or null            | Capacity-limited maximum notional for YES side (internal precision); `null` if capacity unknown                                                                                                                                                                |
| `category`                                                                          | string                    | Market category                                                                                                                                                                                                                                                |
| `close_time`                                                                        | string (ISO 8601) or null | When the market resolves                                                                                                                                                                                                                                       |
| `discovered_at`                                                                     | string (ISO 8601)         | When this market was first discovered and listed on the platform. Sort by it with `sort=discovered_at_desc` to surface the newest markets first.                                                                                                               |
| `fees.lifetime_fee_apr_bps`                                                         | integer                   | Annual fee rate on borrowed capital, i.e. notional − collateral (2000 = 20% APR)                                                                                                                                                                               |
| `fees.liquidation_fee_bps`                                                          | integer                   | Fee charged on liquidation, applied to borrowed capital (1000 = 10%)                                                                                                                                                                                           |
| `fees.origination_tiers`                                                            | array                     | Fee tiers by leverage bracket                                                                                                                                                                                                                                  |
| `id`                                                                                | string                    | Market ID                                                                                                                                                                                                                                                      |
| `latest_enter_at`                                                                   | string (ISO 8601) or null | Latest time a new position can be opened                                                                                                                                                                                                                       |
| `leverage.max_market_leverage_per_notional.{yes,no}.at{100,500,1000,10000}_usd_bps` | integer                   | Maximum market leverage per side broken out by position notional ($100 / $500 / $1,000 / $10,000). Slippage grows with notional, so larger notionals have lower max leverage. A UI slider should publish the bucket that matches the user's selected notional. |
| `leverage.max_no_bps`                                                               | integer                   | Maximum leverage on the NO side (100000 = 10x)                                                                                                                                                                                                                 |
| `leverage.max_yes_bps`                                                              | integer                   | Maximum leverage on the YES side (100000 = 10x). May differ from `max_no_bps` on skewed markets due to per-side fee-tolerance caps.                                                                                                                            |
| `leverage.min_bps`                                                                  | integer                   | Minimum leverage (20000 = 2x)                                                                                                                                                                                                                                  |
| `leverage.step_bps`                                                                 | integer                   | Leverage must be a multiple of this (2500 = 0.25x steps)                                                                                                                                                                                                       |
| `max_notional_no_usd`                                                               | string or null            | Maximum notional you can open on the NO side right now — the lesser of slippage, capacity, your partner's remaining position limit, and the per-user position limit for a wallet with no open positions (dollar display)                                       |
| `max_notional_no_usd_pips`                                                          | string or null            | Maximum notional you can open on the NO side right now — the lesser of slippage, capacity, your partner's remaining position limit, and the per-user position limit for a wallet with no open positions (internal precision)                                   |
| `max_notional_yes_usd`                                                              | string or null            | Maximum notional you can open on the YES side right now — the lesser of slippage, capacity, your partner's remaining position limit, and the per-user position limit for a wallet with no open positions (dollar display)                                      |
| `max_notional_yes_usd_pips`                                                         | string or null            | Maximum notional you can open on the YES side right now — the lesser of slippage, capacity, your partner's remaining position limit, and the per-user position limit for a wallet with no open positions (internal precision)                                  |
| `min_collateral_usd`                                                                | string                    | Minimum collateral (dollar display)                                                                                                                                                                                                                            |
| `min_collateral_usd_pips`                                                           | string                    | Minimum collateral (internal precision). A request with `notional / leverage` below this floor is rejected.                                                                                                                                                    |
| `min_notional_usd`                                                                  | string                    | Minimum notional (dollar display)                                                                                                                                                                                                                              |
| `min_notional_usd_pips`                                                             | string                    | Minimum notional (internal precision)                                                                                                                                                                                                                          |
| `polymarket`                                                                        | object                    | Polymarket identifiers for mapping this market onto Polymarket's own data feeds. Always present (all live markets are Polymarket-sourced).                                                                                                                     |
| `polymarket.condition_id`                                                           | string or null            | Polymarket CTF condition ID. Use it to look the market up on Polymarket's CLOB and Gamma APIs. `null` for the rare market where Polymarket has not exposed a condition ID.                                                                                     |
| `polymarket.no_token_id`                                                            | string                    | Polymarket CLOB token ID (ERC1155 position token ID) for the NO outcome.                                                                                                                                                                                       |
| `polymarket.slug`                                                                   | string                    | Polymarket market slug, matching the slug in Polymarket URLs and Gamma API responses. Same value as the legacy `ticker` field.                                                                                                                                 |
| `polymarket.yes_token_id`                                                           | string                    | Polymarket CLOB token ID (ERC1155 position token ID) for the YES outcome.                                                                                                                                                                                      |
| `prices`                                                                            | object or null            | Latest bid/ask prices. Only present when `expand=prices` is requested. Null if no recent data.                                                                                                                                                                 |
| `prices.no_ask_price_usd`                                                           | string                    | NO side ask price (dollar display)                                                                                                                                                                                                                             |
| `prices.no_ask_price_usd_pips`                                                      | string                    | NO side ask price (internal precision)                                                                                                                                                                                                                         |
| `prices.no_bid_price_usd`                                                           | string                    | NO side bid price (dollar display)                                                                                                                                                                                                                             |
| `prices.no_bid_price_usd_pips`                                                      | string                    | NO side bid price (internal precision)                                                                                                                                                                                                                         |
| `prices.yes_ask_price_usd`                                                          | string                    | YES side ask price (dollar display)                                                                                                                                                                                                                            |
| `prices.yes_ask_price_usd_pips`                                                     | string                    | YES side ask price (internal precision, 10000 pips = $1)                                                                                                                                                                                                       |
| `prices.yes_bid_price_usd`                                                          | string                    | YES side bid price (dollar display)                                                                                                                                                                                                                            |
| `prices.yes_bid_price_usd_pips`                                                     | string                    | YES side bid price (internal precision)                                                                                                                                                                                                                        |
| `provider`                                                                          | string                    | `polymarket`                                                                                                                                                                                                                                                   |
| `rejection_reason_code`                                                             | string or null            | Why this market is not accepting positions on **either** side (see table below). `null` if at least one side accepts. For per-side detail use `sided_eligibility.{yes,no}.rejection_reason_code`.                                                              |
| `sided_eligibility.no.accepting_new_positions`                                      | boolean                   | Whether the NO side is accepting new positions.                                                                                                                                                                                                                |
| `sided_eligibility.no.rejection_reason_code`                                        | string or null            | Why the NO side is not accepting positions; `null` when accepting.                                                                                                                                                                                             |
| `sided_eligibility.yes.accepting_new_positions`                                     | boolean                   | Whether the YES side is accepting new positions. A market with healthy YES depth but thin/saturated NO can be `true` on YES and `false` on NO.                                                                                                                 |
| `sided_eligibility.yes.rejection_reason_code`                                       | string or null            | Why the YES side is not accepting positions; `null` when accepting. Codes match the table below.                                                                                                                                                               |
| `slippage_max_notional_no_usd`                                                      | string or null            | Slippage-limited maximum notional for NO side (dollar display)                                                                                                                                                                                                 |
| `slippage_max_notional_no_usd_pips`                                                 | string or null            | Slippage-limited maximum notional for NO side (internal precision); `null` if slippage data unavailable                                                                                                                                                        |
| `slippage_max_notional_yes_usd`                                                     | string or null            | Slippage-limited maximum notional for YES side (dollar display)                                                                                                                                                                                                |
| `slippage_max_notional_yes_usd_pips`                                                | string or null            | Slippage-limited maximum notional for YES side (internal precision); `null` if slippage data unavailable                                                                                                                                                       |
| `status`                                                                            | string                    | `active`, `closed`, `determined`, `finalized`, or `disputed`                                                                                                                                                                                                   |
| `tags`                                                                              | string\[]                 | Descriptive tags                                                                                                                                                                                                                                               |
| `ticker`                                                                            | string                    | **Deprecated** — use `polymarket.slug`. Unique market ticker sourced from the upstream trading venue (the Polymarket slug). Still accepted in quote requests and path params.                                                                                  |
| `title`                                                                             | string or null            | Human-readable market title                                                                                                                                                                                                                                    |
| `yes_sub_title`                                                                     | string or null            | Description of the "yes" outcome                                                                                                                                                                                                                               |

> **Note:** `ticker` and "slug" refer to the same identifier — the terms are used interchangeably across our docs and integrations.

**Rejection reason codes:**

| Code                                 | Meaning                                                      |
| ------------------------------------ | ------------------------------------------------------------ |
| `QUOTE_MARKET_NOT_ACTIVE`            | Market status is not `active`                                |
| `QUOTE_MARKET_UNSUPPORTED_CATEGORY`  | Market category is not supported (only `crypto` and `sport`) |
| `QUOTE_MARKET_OPEN_INTEREST_TOO_LOW` | Open interest is below the minimum threshold                 |
| `QUOTE_MARKET_RISK_TOO_HIGH`         | Market risk level is not `low`                               |
| `QUOTE_TRADING_WINDOW_CLOSING`       | Market is too close to its trading window end                |
| `QUOTE_HARD_EXIT_TOO_CLOSE`          | *(deprecated, alias for QUOTE\_TRADING\_WINDOW\_CLOSING)*    |
| `QUOTE_ENTRY_EXCLUDED_SPORT`         | Sport type is excluded from entry                            |
| `QUOTE_ENTRY_EXCLUDED_MARKET_TYPE`   | Market type (e.g. first-half moneyline) is excluded          |
| `QUOTE_ENTRY_SPREAD_TOO_WIDE`        | Order book spread (absolute) exceeds maximum                 |
| `QUOTE_ENTRY_DEPTH_TOO_LOW`          | Order book depth is below minimum                            |
| `QUOTE_ENTRY_BID_DEPTH_TOO_LOW`      | Minimum bid depth across both sides is below threshold       |
| `QUOTE_ENTRY_MARKET_TOO_ELAPSED`     | Market has passed too much of its lifetime                   |
| `QUOTE_ENTRY_TOP_HOLDER_TOO_HIGH`    | Top holder concentration exceeds maximum                     |
| `QUOTE_ENTRY_VOLUME_TOO_LOW`         | 24-hour trading volume is below minimum                      |
| `QUOTE_ENTRY_PRICE_OUT_OF_RANGE`     | Mid price is outside the allowed range                       |

***

### Get market

Returns a single market by ticker. Same shape as a list item (not wrapped in `data` array).

```
GET /prediction-markets/markets/{ticker}
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const market = await client.getMarket("will-btc-hit-100k-2025");
```

**Auth:** User JWT or partner API key

**Response: `200 OK`** — Single market object.

**Errors:**

| Status | Code                        |
| ------ | --------------------------- |
| 404    | `customer_market_not_found` |

***

### Get contract info

Returns the vault contract address on Polygon and the public address of the authorized quote signer. Use this to verify that quote responses have not been tampered with by a man-in-the-middle.

```
GET /prediction-markets/contract-info
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const info = await client.getContractInfo();
// info.polygonVaultContractAddress, info.polygonUsdcTokenAddress, info.polygonSignerAddress
```

**Auth:** Public

**Response: `200 OK`**

```json
{
  "evm_chain_id": "137",
  "polygon_signer_address": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
  "polygon_usdc_token_address": "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB",
  "polygon_vault_contract_address": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc"
}
```

**Field reference:**

| Field                            | Type   | Description                                                                                                                                         |
| -------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `evm_chain_id`                   | string | EVM chain ID (`"137"` for Polygon mainnet)                                                                                                          |
| `polygon_signer_address`         | string | Checksummed address of the authorized signer on Polygon                                                                                             |
| `polygon_usdc_token_address`     | string | Checksummed address of the pUSD stablecoin token — the **only** token accepted as collateral. Use it as the transfer target when funding a position |
| `polygon_vault_contract_address` | string | Checksummed address of the vault contract on Polygon                                                                                                |

> **Tip:** These values are static. Fetch them once at startup and cache.

#### Verifying a quote signature

Before submitting an on-chain transaction, verify the quote's `contract_signature` was produced by the authorized signer. Reconstruct the message hash from the quote fields, recover the signer, and compare to `polygon_signer_address`:

```javascript
import {ethers} from "ethers";

const messageHash = ethers.solidityPackedKeccak256(
  [
    "string", "bytes16", "address", "bytes32", "uint256",
    "uint256", "uint32", "uint256", "uint16", "uint16",
    "uint16", "uint256", "uint256", "address",
  ],
  [
    "CREATE_POSITION",
    quote.position_seed_hex,
    userWalletAddress,
    quote.polymarket_market_id,
    BigInt(quote.polymarket_token_id),
    BigInt(quote.collateral_usdc_units),
    quote.leverage_bps,
    BigInt(quote.notional_usdc_units),
    quote.origination_fee_bps,
    quote.lifetime_fee_apr_bps,
    quote.liquidation_fee_bps,
    BigInt(quote.signature_expiry),
    BigInt(contractInfo.evm_chain_id),
    contractInfo.polygon_vault_contract_address,
  ]
);

const recoveredSigner = ethers.verifyMessage(
  ethers.getBytes(messageHash),
  quote.contract_signature
);

if (recoveredSigner.toLowerCase() !== contractInfo.polygon_signer_address.toLowerCase()) {
  throw new Error("Signature verification failed");
}
```

Also verify that `polygon_vault_contract_address` and `evm_chain_id` match the corresponding fields in the quote.

***

## 2. Auth

### Generate token

Generate a user-scoped JWT. The partner is responsible for verifying wallet ownership before calling.

```
POST /prediction-markets/tokens
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
// You don't call this endpoint directly — the auth providers exchange your
// credentials for a JWT and refresh it automatically:
const client = new DimesClient({ auth: new ApiKeyAuth({ apiKey, walletAddress }) }); // server-side
// In the browser: new JwtAuth({ tokenUrl: "https://your-backend.com/api/dimes-token" })
```

**Auth:** Partner API key

**Request:**

```json
{
  "wallet_address": "0x1234...abcd"
}
```

| Field            | Type   | Required | Validation                             |
| ---------------- | ------ | -------- | -------------------------------------- |
| `wallet_address` | string | yes      | Valid EVM address or Solana public key |

**Response: `201 Created`**

```json
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_at": "2025-06-01T11:00:00.000Z"
}
```

**Errors:**

| Status | Code                                   |
| ------ | -------------------------------------- |
| 401    | `unauthorized`                         |
| 400    | `customer_auth_invalid_wallet_address` |

***

## 3. Quotes

### Create quote

Create a new quote (step 1 of opening a position). Returns pricing, fees, liquidation parameters, and a transaction to sign.

```
POST /prediction-markets/quotes
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
// Recommended — executeQuote runs the full draft → promote flow with auto-correction:
const { quote, corrections } = await executeQuote(client, {
  marketTicker: "will-btc-hit-100k-2025",
  side: "yes",
  collateralUsd: 25,
  leverageBps: 50_000, // 5x
  slippageBps: 300,
});
// Low-level single call (params already finalized):
const direct = await client.createQuote(buildQuoteParams({
  marketTicker: "will-btc-hit-100k-2025", side: "yes", collateralUsd: 25, leverageBps: 50_000, slippageBps: 300,
}));
```

**Auth:** User JWT

**Rate limit:** 1 request per second for each authenticated wallet within a partner integration.

**Request:**

```json
{
  "market_ticker": "will-btc-hit-100k-2025",
  "effective_side": "yes",
  "leverage_bps": 50000,
  "notional_usd_pips": "250000000",
  "slippage_bps": 300,
  "provider": "polymarket",
  "allow_revision": false
}
```

| Field                | Type    | Required | Validation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| -------------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `market_ticker`      | string  | yes      | Market ticker                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `effective_side`     | string  | yes      | `yes` or `no`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `leverage_bps`       | integer | yes      | 20000–100000, multiple of 2500                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `notional_usd_pips`  | string  | yes      | Minimum `10000`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `slippage_bps`       | integer | yes      | 100–1000                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `provider`           | string  | no       | `polymarket` (default)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `allow_revision`     | boolean | no       | `false` (default). Opt in to server-side notional/leverage revision — see [Quote revisions](#quote-revisions).                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `allow_partial_fill` | boolean | no       | `false` (default) — the order is atomic (fully filled or reverted). `true` opts into partial-open: the position opens at the actually-filled size. See [Partial-Open (FAK)](/for-developers/order-types/partial-open.md).                                                                                                                                                                                                                                                                                                              |
| `min_fill_bps`       | integer | no       | Only valid with `allow_partial_fill: true`. Range `2000`–`5000`, multiple of `500` (5% steps). The minimum fraction of the requested notional the user will accept. Capped from below by `max(2000, ceil(MIN_COLLATERAL × 10000 / requested_collateral), ceil(MIN_NOTIONAL × 10000 / requested_notional))` so a worst-case partial fill cannot drop below the minimum collateral **or** the minimum notional — see `quote_min_fill_bps_below_floor` in [error handling](/for-developers/api-and-events/error-handling.md#post-quotes). |

**Response: `201 Created`**

```json
{
  "id": "dm_off_abc123",
  "market_ticker": "will-btc-hit-100k-2025",
  "wallet_address": "0x1234...abcd",
  "effective_side": "yes",
  "provider": "polymarket",
  "leverage_bps": 50000,
  "notional_usd_pips": "250000000",
  "notional_usd": "25000.00",
  "entry_price_usd_pips": "6500",
  "entry_price_usd": "0.65",
  "origination_fee_bps": 125,
  "origination_fee_usd_pips": "625000",
  "origination_fee_usd": "0.63",
  "protocol_origination_fee_bps": 100,
  "protocol_origination_fee_usd_pips": "500000",
  "protocol_origination_fee_usd": "0.50",
  "partner_origination_fee_bps": 25,
  "partner_origination_fee_usd_pips": "125000",
  "partner_origination_fee_usd": "0.13",
  "polymarket_trading_fee_bps": 100,
  "liquidation_fee_bps": 1000,
  "current_liquidation_price_usd_pips": "3500",
  "current_liquidation_price_usd": "0.35",
  "expected_open_trading_fee_usd_pips": "225",
  "expected_open_trading_fee_usd": "0.02",
  "min_expected_position_token_units": "9900000",
  "total_user_amount_usd_pips": "5625000",
  "total_user_amount_usd": "562.50",
  "expires_at": "2025-06-01T10:05:00.000Z",
  "position_seed": "abc123...",
  "position_seed_hex": "0xa1b2c3d4e5f67890abcdef1234567890",
  "on_chain_position_key": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890",
  "swap_transaction": "base64-encoded-solana-tx...",
  "evm_chain_id": "137",
  "polymarket_market_id": "0xabcdef...",
  "contract_signature": "0xabc...",
  "polymarket_token_id": "52114319501245915516055106046884209969926127482827954674443846427813813222426",
  "polygon_vault_contract_address": "0x1234...5678",
  "signature_expiry": "1717236300",
  "revision": "accepted_as_requested",
  "requested_leverage_bps": 50000,
  "requested_notional_usd_pips": "250000000"
}
```

**Expanding max gain (`?expand=max_gain`)**

Add `?expand=max_gain` to any quote endpoint (`/quotes`, `/draft-quotes`, `/promoted-quotes/{id}`) to include a `max_gain` object — the expected profit on a win (profit over principal). It is omitted unless requested.

```json
"max_gain": {
"gross_max_gain_usd": "138.46",
"gross_max_gain_usd_pips": "1384600",
"gross_max_gain_usdc_units": "138460000",
"net_max_gain_usd": "137.21",
"net_max_gain_usd_pips": "1372100",
"net_max_gain_usdc_units": "137210000"
}
```

`gross_max_gain` is the position's value on a win (tokens redeemed at $1 via settlement) minus the notional, before fees. `net_max_gain` also subtracts the open trading fee and origination fee. It assumes settlement (no exit trading fee) and excludes time-based lifetime fees, so it is an upper bound — and may be negative for high-price entries.

| Field                                                         | Description                                                                                                                                                                                                                                         |
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contract_signature`                                          | EIP-191 signature for contract create position                                                                                                                                                                                                      |
| `current_liquidation_price_usd_pips` / `_usd`                 | Price triggering liquidation                                                                                                                                                                                                                        |
| `effective_side`                                              | `yes` or `no`                                                                                                                                                                                                                                       |
| `entry_price_usd_pips` / `_usd`                               | Entry price                                                                                                                                                                                                                                         |
| `evm_chain_id`                                                | Chain ID for EVM signature (EVM only)                                                                                                                                                                                                               |
| `expected_open_trading_fee_usd_pips` / `_usd` / `_usdc_units` | Expected exchange trading fee. Pass the `_usdc_units` value as the contract's `venueFeeUsdcUnits` parameter. Refunded in full on cancel or revert.                                                                                                  |
| `expires_at`                                                  | Quote expiry (ISO 8601). The validity window is short and may change without notice — always read this field from the response and do not hardcode a duration. Requests submitted after this timestamp will be rejected; fetch a new quote instead. |
| `id`                                                          | Quote ID                                                                                                                                                                                                                                            |
| `leverage_bps`                                                | Leverage in basis points                                                                                                                                                                                                                            |
| `liquidation_fee_bps`                                         | Fee charged on liquidation in basis points                                                                                                                                                                                                          |
| `market_ticker`                                               | Market ticker                                                                                                                                                                                                                                       |
| `min_expected_position_token_units`                           | Minimum tokens expected (1,000,000 units = 1 token)                                                                                                                                                                                                 |
| `notional_usd_pips` / `_usd`                                  | Notional exposure                                                                                                                                                                                                                                   |
| `on_chain_position_key`                                       | On-chain position key (bytes32) that will be derived on `createPosition`. Matches `on_chain_position_key` on the position response — use it to link a quote to its future position                                                                  |
| `origination_fee_bps`                                         | Combined fee rate at open (`protocol + partner`)                                                                                                                                                                                                    |
| `origination_fee_usd_pips` / `_usd`                           | Combined absolute fee at open                                                                                                                                                                                                                       |
| `partner_origination_fee_bps`                                 | Partner component of the origination fee in basis points *(deprecated — prefer builder code fees)*                                                                                                                                                  |
| `partner_origination_fee_usd_pips` / `_usd`                   | Partner component in absolute terms *(deprecated — prefer builder code fees)*                                                                                                                                                                       |
| `polygon_vault_contract_address`                              | Vault contract address on Polygon                                                                                                                                                                                                                   |
| `polymarket_market_id`                                        | On-chain bytes32 Polymarket market identifier                                                                                                                                                                                                       |
| `polymarket_token_id`                                         | Polymarket ERC1155 conditional token ID for the selected side                                                                                                                                                                                       |
| `polymarket_trading_fee_bps`                                  | Polymarket venue trading fee rate (applied to the expected open trading fee). `0` for Kalshi. The breakdown is only present on the offer response; historical position entries expose only the combined `origination_fee_*` values.                 |
| `position_seed`                                               | Seed for on-chain account derivation                                                                                                                                                                                                                |
| `position_seed_hex`                                           | Position seed as 0x-prefixed bytes16 hex — contract-ready value for `createPosition`                                                                                                                                                                |
| `protocol_origination_fee_bps`                                | Protocol component of the origination fee in basis points                                                                                                                                                                                           |
| `protocol_origination_fee_usd_pips` / `_usd`                  | Protocol component in absolute terms                                                                                                                                                                                                                |
| `provider`                                                    | `polymarket`                                                                                                                                                                                                                                        |
| `requested_leverage_bps`                                      | Leverage the caller sent in the request. Equal to `leverage_bps` when `revision === "accepted_as_requested"`.                                                                                                                                       |
| `requested_notional_usd_pips`                                 | Notional the caller sent in the request. Equal to `notional_usd_pips` when `revision === "accepted_as_requested"`.                                                                                                                                  |
| `revision`                                                    | Signals whether the returned quote matches the request. One of `accepted_as_requested`, `notional_reduced`, `leverage_reduced`, or `notional_and_leverage_reduced`. See [Quote revisions](#quote-revisions).                                        |
| `signature_expiry`                                            | Unix timestamp when the EVM signature expires (EVM only). Always read this from the response — the validity window is short and may change without notice.                                                                                          |
| `swap_transaction`                                            | Base64-encoded Solana transaction (Solana only)                                                                                                                                                                                                     |
| `total_user_amount_usd_pips` / `_usd`                         | Total economic cost to open the position. Polymarket: collateral + origination fee + expected trading fee. The EVM contract pulls `collateral + origination fee + venueFee` via `safeTransferFrom` at `createPosition`.                             |
| `wallet_address`                                              | Wallet address (from JWT)                                                                                                                                                                                                                           |

### Partial-open (FAK)

By default, quotes open atomically: the order either fills its full requested notional in one FOK match or reverts and refunds the user (no position is created). For thinner markets, set `allow_partial_fill: true` (optionally with a `min_fill_bps` floor) to open at the actually-filled size instead.

```json
{
  "market_ticker": "will-btc-hit-100k-2025",
  "effective_side": "yes",
  "leverage_bps": 20000,
  "notional_usd_pips": "1000000000",
  "slippage_bps": 200,
  "allow_partial_fill": true,
  "min_fill_bps": 5000
}
```

The offer and position responses echo `allow_partial_fill` and `min_fill_bps` so the caller can confirm what the user signed. The full lifecycle (floor leg, FAK retries, `finalizeOpenPartial` shrink/refund), the `min_fill_bps` floor rules, the progress/floor-missed notifications, and the `quote_min_fill_bps_below_floor` rejection are documented on the dedicated [Partial-Open (FAK)](/for-developers/order-types/partial-open.md) page.

### Quote revisions

By default (`allow_revision: false`), the API will not silently change the requested `notional_usd_pips` or `leverage_bps`. If the book or the on-chain collateral floor would force a reduction, the request is rejected with `400 QUOTE_REVISION_REQUIRED` and the response carries the parameters that *would* have been acceptable, so the caller can re-quote with values it explicitly agrees to:

```json
{
  "error": {
    "type": "INVALID_REQUEST_ERROR",
    "code": "QUOTE_REVISION_REQUIRED",
    "message": "Offer cannot be honored at the requested parameters (...)",
    "params": {
      "revision": "leverage_reduced",
      "requested_leverage_bps": 80000,
      "requested_notional_usd_pips": "70000",
      "acceptable_leverage_bps": 70000,
      "acceptable_notional_usd_pips": "70000",
      "acceptable_collateral_usdc_units": "1000000"
    }
  }
}
```

`params.revision` is one of `notional_reduced`, `leverage_reduced`, or `notional_and_leverage_reduced` — the kind of revision that would have been applied. The `acceptable_*` fields describe the largest position the API can produce at or below the original request; callers may resubmit with these exact values (and `allow_revision` may stay `false`).

Pass `allow_revision: true` only if you want the server to revise the quote on your behalf — useful for integrations that already expect to compare `leverage_bps` / `notional_usd_pips` against `requested_leverage_bps` / `requested_notional_usd_pips` on the success response. With `allow_revision: true` the adjustments happen in a fixed order:

1. **Notional capping.** The capacity reservation fills as much of the requested notional as clears within the requested `slippage_bps`, preserving the requested leverage. Output: `revision === "notional_reduced"`.
2. **Leverage clamping.** Leverage may be lowered (rounded down to the nearest 2500 bps step) for either of two reasons: the capped notional at the requested leverage would produce `collateral_usdc_units < 1_000_000` (the vault's `CollateralBelowMinimum` floor), or the market's risk parameters cap leverage below what was requested. Output: `revision === "leverage_reduced"` (or `"notional_and_leverage_reduced"` if step 1 also fired, or if the risk cap forces notional down as well).
3. **Rejection.** If clamping would drop leverage below 15000 bps (1.5×), the API returns `400 Bad Request` with the `LIQUIDITY_INSUFFICIENT` error — the book is too thin to support a viable position.

The invariant `notional_usdc_units === collateral_usdc_units × leverage_bps / 10_000` always holds on the returned quote (matches the EIP-712 payload signed by the API).

**Errors:** See [Error Handling — Quotes](/for-developers/api-and-events/error-handling.md#post-quotes).

### Draft quotes

Draft quotes compute the same pricing, fees, leverage, and liquidation numbers as a regular quote but do **not** reserve capacity or generate a chain signature. Use them for display purposes (e.g. showing estimated terms before the user commits) without consuming capacity that could block actual trades.

```
POST /prediction-markets/draft-quotes
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const draft = await client.createDraftQuote(buildQuoteParams({
  marketTicker: "will-btc-hit-100k-2025", side: "yes", collateralUsd: 25, leverageBps: 50_000, slippageBps: 300,
}));
```

**Auth:** User JWT

**Rate limit:** 1 request per second for each authenticated wallet within a partner integration.

**Request:** Identical to [Create quote](#create-quote) (same body fields and validation).

**Response: `201 Created`**

The response shape is the same as a regular quote with these differences:

| Field                   | Value in draft quote                                           |
| ----------------------- | -------------------------------------------------------------- |
| `id`                    | Draft quote ID (`dm_dro_...`)                                  |
| `contract_signature`    | Empty string — no chain signature is generated                 |
| `evm_chain_id`          | Empty string                                                   |
| `signature_expiry`      | `"0"`                                                          |
| `swap_transaction`      | Absent                                                         |
| `position_seed`         | Empty string — no position seed is allocated                   |
| `position_seed_hex`     | Empty string                                                   |
| `on_chain_position_key` | Empty string                                                   |
| `expires_at`            | Current timestamp (draft quotes do not have a validity window) |

All pricing and fee fields (`entry_price_*`, `origination_fee_*`, `liquidation_*`, `total_user_amount_*`, etc.) are computed identically to a regular quote.

A draft quote **cannot** be used to open a position directly. Instead, promote it to a real quote using the endpoint below.

**Errors:** Same as [Error Handling — Quotes](/for-developers/api-and-events/error-handling.md#post-quotes), except capacity and position limit errors (`QUOTE_SIDE_CAPACITY_EXCEEDED`, `USER_POSITION_LIMIT_EXCEEDED`, etc.) are not returned since draft quotes do not reserve capacity.

### Promote draft quote

Promote a draft quote to a real, executable quote. The backend loads the draft's parameters and re-runs the full quote pipeline, returning a signed quote that can be submitted on-chain.

Recommended flow:

1. Call `POST /prediction-markets/draft-quotes` to get pricing — display it to the user
2. When the user is ready, call `POST /prediction-markets/promoted-quotes/{draft_quote_id}`
3. On success, immediately submit the signed quote to the contract

If market conditions changed between the draft and promotion, the endpoint returns the same errors as a regular quote. The user can retry (step 1) to get fresh numbers.

```
POST /prediction-markets/promoted-quotes/{draft_quote_id}
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const quote = await client.promoteDraftQuote(draft.id);
```

**Auth:** User JWT (must match the wallet that created the draft)

**Rate limit:** 1 request per second for each authenticated wallet within a partner integration.

**Path parameters:**

| Parameter        | Type   | Description                        |
| ---------------- | ------ | ---------------------------------- |
| `draft_quote_id` | string | Draft quote ID (from step 1 above) |

**Request body:** Empty (all parameters are loaded from the draft).

**Response: `201 Created`**

Same shape as [Create quote](#create-quote) — a fully signed quote with `contract_signature`, `position_seed`, `signature_expiry`, and all pricing fields populated.

**Errors:**

| Status | Code                         | Description                                                       |
| ------ | ---------------------------- | ----------------------------------------------------------------- |
| `404`  | —                            | Draft not found, or wallet/partner does not match the draft owner |
| `400`  | Same as regular quote errors | Market conditions changed since the draft                         |

Promoting the same draft multiple times is allowed — each call creates a new independent quote. Only one can be used on-chain (position seeds are unique per quote).

***

## 4. Positions (User JWT)

### List positions

List positions for the authenticated user. Scoped to `(wallet_address, partner_id)` from JWT.

```
GET /prediction-markets/positions
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const positions = await client.getPositions({ status: "open" });
// positions: Position[] — narrow with isOpenPosition() / isClosedPosition()
```

**Auth:** User JWT

**Query parameters:**

| Param                 | Type    | Default      | Description                                                                                                                                                                                                                                                           |
| --------------------- | ------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`              | string  | —            | Filter by a single status: `pending`, `open`, `unwinding`, `closing`, `settling`, `closed`, `settled`, `liquidated`, `cancelled`. `open` includes positions currently being unwound or partially closed for backwards compatibility. Mutually exclusive with `state`. |
| `state`               | string  | —            | Filter by lifecycle group: `active` (in-flight: `pending`, `open`, `unwinding`, `closing`, `settling`) or `inactive` (terminal: `closed`, `settled`, `liquidated`, `cancelled`). Mutually exclusive with `status`.                                                    |
| `market_ticker`       | string  | —            | Filter by market ticker                                                                                                                                                                                                                                               |
| `polymarket_token_id` | string  | —            | Filter by Polymarket conditional token ID                                                                                                                                                                                                                             |
| `sort_by`             | string  | `created_at` | Sort field: `created_at`, `closed_at`                                                                                                                                                                                                                                 |
| `sort_direction`      | string  | `desc`       | Sort order: `asc`, `desc`                                                                                                                                                                                                                                             |
| `limit`               | integer | 25           | Max results (1–100)                                                                                                                                                                                                                                                   |
| `starting_after`      | string  | —            | Cursor: position ID                                                                                                                                                                                                                                                   |
| `ending_before`       | string  | —            | Cursor: position ID                                                                                                                                                                                                                                                   |
| `expand`              | string  | —            | Comma-separated list of related sub-resources to embed inline in each position. Allowed values: `unwinds`. See [Expanding sub-resources](#expanding-sub-resources).                                                                                                   |

**Response: `200 OK`** — Open position:

```json
{
  "data": [
    {
      "id": "dm_pos_abc123",
      "created_at": "2025-06-01T09:59:55.000Z",
      "on_chain_position_key": "0x1a2b3c...",
      "market_ticker": "will-btc-hit-100k-2025",
      "market_title": "Will BTC hit $100K?",
      "provider": "polymarket",
      "status": "open",
      "effective_side": "yes",
      "wallet_address": "0x1234...abcd",
      "effective_leverage_bps": 84000,
      "failure": null,
      "close_attempt": null,
      "entry": {
        "collateral_usd_pips": "50000000",
        "collateral_usd": "50.00",
        "notional_usd_pips": "250000000",
        "notional_usd": "25000.00",
        "leverage_bps": 50000,
        "price_usd_pips": "6500",
        "price_usd": "0.65",
        "effective_entry_price_usd_pips": "6533",
        "effective_entry_price_usd": "0.6533",
        "effective_slippage_bps": 51,
        "initial_fill_bps": 9950,
        "origination_fee_bps": 125,
        "protocol_origination_fee_bps": 100,
        "partner_origination_fee_bps": 25,
        "origination_fee_usd_pips": "625000",
        "origination_fee_usd": "0.63",
        "opened_at": "2025-06-01T10:00:00.000Z",
        "open_latency_ms": 12500
      },
      "current": {
        "book_leverage_bps": 35000,
        "mark_price_usd_pips": "7000",
        "mark_price_usd": "0.70",
        "market_leverage_bps": 38500,
        "notional_usd_pips": "200000000",
        "notional_usd": "20000.00",
        "position_token_units": "384615",
        "remaining_bps": 7500,
        "collateral_usd_pips": "50000000",
        "collateral_usd": "50.00",
        "effective_collateral_usd_pips": "42000000",
        "effective_collateral_usd": "42.00",
        "unrealized_pnl_usd_pips": "-8000000",
        "unrealized_pnl_usd": "-8.00",
        "unrealized_pnl_bps": -1600,
        "net_unrealized_pnl_usd_pips": "-9200000",
        "net_unrealized_pnl_usd": "-9.20",
        "net_unrealized_pnl_bps": -1840,
        "position_value_usd_pips": "242000000",
        "position_value_usd": "24200.00"
      },
      "risk": {
        "health_bps": 7500,
        "current_liquidation_price_usd_pips": "3200",
        "current_liquidation_price_usd": "0.32",
        "liquidation_buffer_bps": 5077,
        "liquidation_fee_bps": 1000,
        "margin_buffer_usd_pips": "5000000",
        "margin_buffer_usd": "500.00"
      },
      "fees": {
        "lifetime_fee_apr_bps": 2000,
        "accrued_lifetime_fee_usd_pips": "1200000",
        "accrued_lifetime_fee_usd": "1.20",
        "pending_lifetime_fee_usd_pips": "300000",
        "pending_lifetime_fee_usd": "0.30",
        "accrued_venue_fee_usd_pips": "200000",
        "accrued_venue_fee_usd": "0.20",
        "total_fees_usd_pips": "2325000",
        "total_fees_usd": "2.33"
      },
      "timing": {
        "is_settlement_pending": false,
        "is_voided": false,
        "market_close_time": "2025-09-30T00:00:00.000Z",
        "market_status": "active",
        "time_to_close_minutes": 172800
      }
    }
  ],
  "has_more": false
}
```

**Open position field reference:**

| Field                                | Description                                                                                                                                                                                                                                                                                         |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `created_at`                         | ISO 8601 timestamp when the position record was created                                                                                                                                                                                                                                             |
| `close_attempt`                      | Present when a requested close was deferred because the market resolved before the shares could be sold: `{ outcome: "deferred", reason: "awaiting_settlement", deferred_at: <ISO 8601> }`. The remaining tokens are redeemed at settlement. `null` for any open position without a deferred close. |
| `effective_leverage_bps`             | Time-weighted average structural leverage over position lifetime                                                                                                                                                                                                                                    |
| `effective_side`                     | `yes` or `no`                                                                                                                                                                                                                                                                                       |
| `failure`                            | `{ reason: string }` if the position transaction failed, otherwise `null`                                                                                                                                                                                                                           |
| `id`                                 | Position identifier                                                                                                                                                                                                                                                                                 |
| `market_ticker`                      | Market ticker                                                                                                                                                                                                                                                                                       |
| `market_title`                       | Human-readable market title, or null                                                                                                                                                                                                                                                                |
| `on_chain_position_key`              | On-chain position key (bytes32) — pass directly to `requestClose` or `requestPartialClose`                                                                                                                                                                                                          |
| `provider`                           | `polymarket`                                                                                                                                                                                                                                                                                        |
| `status`                             | `pending`, `open`, `unwinding`, `closing`, `settling`, `closed`, `settled`, `liquidated`, `cancelled`                                                                                                                                                                                               |
| `wallet_address`                     | Wallet address that owns this position                                                                                                                                                                                                                                                              |
| **entry**                            | Snapshot at position creation                                                                                                                                                                                                                                                                       |
| `entry.collateral_*`                 | User's original collateral                                                                                                                                                                                                                                                                          |
| `entry.effective_entry_price_*`      | Actual fill price on the prediction market after execution. `null` until the on-chain fill is recorded.                                                                                                                                                                                             |
| `entry.effective_slippage_bps`       | Execution slippage between the offer's indicative price and the actual fill, in basis points. Signed: positive = adverse fill, negative = favorable. `null` until the fill is recorded.                                                                                                             |
| `entry.initial_fill_bps`             | How much of the requested size was actually filled at open, in basis points (10000 = 100%). Frozen at open — does **not** change when the position is partially closed. Use this for an "opened at X% of requested" indicator. `null` until the open fill is recorded.                              |
| `entry.leverage_bps`                 | Entry leverage (50000 = 5x)                                                                                                                                                                                                                                                                         |
| `entry.notional_*`                   | Original notional                                                                                                                                                                                                                                                                                   |
| `entry.open_latency_ms`              | Milliseconds from position creation to on-chain open confirmation. `null` until fully opened.                                                                                                                                                                                                       |
| `entry.opened_at`                    | Open timestamp (null if still pending)                                                                                                                                                                                                                                                              |
| `entry.origination_fee_*`            | Absolute combined origination fee at open                                                                                                                                                                                                                                                           |
| `entry.origination_fee_bps`          | Combined fee rate at open (`protocol + partner`)                                                                                                                                                                                                                                                    |
| `entry.partner_origination_fee_bps`  | Partner portion of the origination fee in basis points *(deprecated — prefer builder code fees)*                                                                                                                                                                                                    |
| `entry.price_*`                      | Indicative entry price quoted on the offer                                                                                                                                                                                                                                                          |
| `entry.protocol_origination_fee_bps` | Protocol portion of the origination fee in basis points                                                                                                                                                                                                                                             |
| **current**                          | Live state (affected by force unwinds)                                                                                                                                                                                                                                                              |
| `current.book_leverage_bps`          | Current book-value leverage in basis points (20000 = 2x). Only changes when capital is returned via unwind.                                                                                                                                                                                         |
| `current.collateral_*`               | Original collateral (unchanged by unwinds)                                                                                                                                                                                                                                                          |
| `current.effective_collateral_*`     | What user would net after repaying loan if closed now. Floored at 0.                                                                                                                                                                                                                                |
| `current.mark_price_*`               | Current market mid price                                                                                                                                                                                                                                                                            |
| `current.market_leverage_bps`        | Current market-value leverage in basis points, computed from the live oracle price. `null` when the position is insolvent (equity ≤ 0).                                                                                                                                                             |
| `current.net_unrealized_pnl_*`       | Unrealized PnL net of all fees (origination + pending lifetime + accrued venue)                                                                                                                                                                                                                     |
| `current.net_unrealized_pnl_bps`     | Net unrealized PnL as return on equity in basis points                                                                                                                                                                                                                                              |
| `current.notional_*`                 | Current notional (reduced by unwinds)                                                                                                                                                                                                                                                               |
| `current.position_token_units`       | Token quantity held (1,000,000 units = 1 token)                                                                                                                                                                                                                                                     |
| `current.position_value_*`           | `tokens × mark_price`                                                                                                                                                                                                                                                                               |
| `current.remaining_bps`              | Fraction of the originally opened size still held, in basis points (10000 = 100%). Legitimately decreases after each partial close (e.g. 7000 = 70% remaining after a 30% close) — not a fill problem. `null` until the open fill is recorded.                                                      |
| `current.unrealized_pnl_*`           | PnL assuming close at mark price                                                                                                                                                                                                                                                                    |
| `current.unrealized_pnl_bps`         | Unrealized PnL as return on equity in basis points                                                                                                                                                                                                                                                  |
| **risk**                             | Liquidation metrics                                                                                                                                                                                                                                                                                 |
| `risk.current_liquidation_price_*`   | Price triggering liquidation                                                                                                                                                                                                                                                                        |
| `risk.health_bps`                    | Margin health 0–10000 (10000 at entry, 0 at liquidation)                                                                                                                                                                                                                                            |
| `risk.liquidation_buffer_bps`        | `(mark_price - liq_price) / mark_price × 10000`                                                                                                                                                                                                                                                     |
| `risk.liquidation_fee_bps`           | Fee on liquidation, applied to borrowed capital (1000 = 10%)                                                                                                                                                                                                                                        |
| `risk.margin_buffer_*`               | Dollar distance to liquidation                                                                                                                                                                                                                                                                      |
| **fees**                             | Fee accruals                                                                                                                                                                                                                                                                                        |
| `fees.accrued_lifetime_fee_*`        | Fees accrued since last unwind or open                                                                                                                                                                                                                                                              |
| `fees.accrued_venue_fee_*`           | Venue (Polymarket/Kalshi) trading fees paid so far on this position (open + any force-unwind legs)                                                                                                                                                                                                  |
| `fees.lifetime_fee_apr_bps`          | Annual rate on borrowed capital, i.e. notional − collateral (2000 = 20% APR)                                                                                                                                                                                                                        |
| `fees.pending_lifetime_fee_*`        | Uncollected fees from prior unwinds                                                                                                                                                                                                                                                                 |
| `fees.total_fees_*`                  | Rollup of all fees so far (origination + accrued lifetime + pending lifetime + accrued venue)                                                                                                                                                                                                       |
| **timing**                           |                                                                                                                                                                                                                                                                                                     |
| `timing.is_settlement_pending`       | Whether settlement is pending (market resolved or voided, settlement not yet executed)                                                                                                                                                                                                              |
| `timing.is_voided`                   | Whether the market was voided (closed with no winner, 50/50 payout at $0.50 per token)                                                                                                                                                                                                              |
| `timing.market_close_time`           | When the market resolves (null if no close time)                                                                                                                                                                                                                                                    |
| `timing.market_status`               | Market status (`active`, `closed`, `determined`, `finalized`, etc.). When `determined` or `finalized`, mark price reflects the settlement outcome ($1 or $0)                                                                                                                                        |
| `timing.time_to_close_minutes`       | Minutes until close (null if no close time)                                                                                                                                                                                                                                                         |

***

**Closed / settled / liquidated positions** replace `current`, `risk`, and `timing` with `close_reason` and `result`:

```json
{
  "id": "dm_pos_xyz789",
  "created_at": "2025-06-01T09:59:55.000Z",
  "market_ticker": "will-eth-merge-succeed",
  "market_title": "Will the Ethereum merge succeed?",
  "provider": "polymarket",
  "status": "settled",
  "effective_side": "yes",
  "wallet_address": "0x1234...abcd",
  "effective_leverage_bps": 84000,
  "failure": null,
  "close_reason": "settled",
  "revert_reason": null,
  "entry": {
    "collateral_usd_pips": "50000000",
    "collateral_usd": "50.00",
    "notional_usd_pips": "250000000",
    "notional_usd": "25000.00",
    "leverage_bps": 50000,
    "price_usd_pips": "6500",
    "price_usd": "0.65",
    "origination_fee_bps": 125,
    "protocol_origination_fee_bps": 100,
    "partner_origination_fee_bps": 25,
    "origination_fee_usd_pips": "625000",
    "origination_fee_usd": "0.63",
    "opened_at": "2025-06-01T10:00:00.000Z",
    "open_latency_ms": 12500
  },
  "result": {
    "closed_at": "2025-07-15T14:30:00.000Z",
    "realized_pnl_usd_pips": "15000000",
    "realized_pnl_usd": "15.00",
    "net_realized_pnl_usd_pips": "13375000",
    "net_realized_pnl_usd": "13.38",
    "net_realized_pnl_bps": 2675,
    "proceeds_usd_pips": "65000000",
    "proceeds_usd": "65.00",
    "exit_notional_usd_pips": "78000000",
    "exit_notional_usd": "78.00",
    "collected_lifetime_fee_usd_pips": "1500000",
    "collected_lifetime_fee_usd": "1.50",
    "collected_liquidation_fee_usd_pips": "0",
    "collected_liquidation_fee_usd": "0.00"
  },
  "fees": {
    "lifetime_fee_apr_bps": 2000,
    "total_lifetime_fee_usd_pips": "1500000",
    "total_lifetime_fee_usd": "1.50",
    "total_venue_fee_usd_pips": "200000",
    "total_venue_fee_usd": "0.20",
    "total_fees_usd_pips": "2325000",
    "total_fees_usd": "2.33"
  }
}
```

> **Deprecated fields on closed `fees`:** `origination_fee_bps`, `protocol_origination_fee_bps`, `partner_origination_fee_bps`, `origination_fee_usd_pips`, `origination_fee_usd` are still emitted for backwards compatibility but duplicate the canonical values on `entry.*`. New integrations should read the origination fields from `entry` only.

| Field                                | Description                                                                                                                                                                                                                                                        |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `close_reason`                       | `closed`, `settled`, `liquidated`, `cancelled`, or `reverted`                                                                                                                                                                                                      |
| `fees.total_fees_*`                  | Total blended fees (origination + lifetime + liquidation + venue)                                                                                                                                                                                                  |
| `fees.total_lifetime_fee_*`          | Total lifetime fees collected at close                                                                                                                                                                                                                             |
| `fees.total_venue_fee_*`             | Total venue (Polymarket/Kalshi) trading fees paid across the position lifetime (open + close/liquidate/settle + force-unwinds)                                                                                                                                     |
| `result.closed_at`                   | When the position was finalized                                                                                                                                                                                                                                    |
| `result.collected_lifetime_fee_*`    | Total lifetime fees collected                                                                                                                                                                                                                                      |
| `result.collected_liquidation_fee_*` | Liquidation fee (0 unless liquidated)                                                                                                                                                                                                                              |
| `result.exit_notional_*`             | Volume-weighted notional realized across all unwinds and the final close (`Σ shares sold × fill price`). Pairs with `entry.notional_*` for an entry-vs-exit view. Null for `reverted`/`cancelled` positions (no shares were ever sold).                            |
| `result.net_realized_pnl_*`          | Realized PnL net of all fees (origination + lifetime + liquidation + venue)                                                                                                                                                                                        |
| `result.net_realized_pnl_bps`        | Net realized PnL as return on equity in basis points                                                                                                                                                                                                               |
| `result.proceeds_*`                  | pUSD returned to user                                                                                                                                                                                                                                              |
| `result.realized_pnl_*`              | Final PnL: `proceeds - collateral`                                                                                                                                                                                                                                 |
| `revert_reason`                      | Why a reverted open failed. Non-null only when `close_reason` is `reverted`: `exchange_unavailable` (venue was temporarily unavailable — safe to retry), `slippage_exceeded` (price moved beyond tolerance before the order filled), or `unknown`. Null otherwise. |

***

### Get position

Get a single position. Must belong to the JWT's `(wallet_address, partner_id)`.

```
GET /prediction-markets/positions/{position_id}
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
// No dedicated single-position method — filter from getPositions():
const position = (await client.getPositions()).find((p) => p.id === positionId);
```

**Auth:** User JWT

**Query parameters:**

| Param    | Type   | Description                                                                                                                                        |
| -------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `expand` | string | Comma-separated list of related sub-resources to embed inline. Allowed values: `unwinds`. See [Expanding sub-resources](#expanding-sub-resources). |

**Response: `200 OK`** — Single position object (not wrapped in `data` array).

**Errors:**

| Status | Code                          |
| ------ | ----------------------------- |
| 404    | `customer_position_not_found` |

***

### Position unwinds (sub-resource)

Each position has an unwinds (deleveraging) history. Fetch it inline by passing `expand=unwinds` to [List positions](#list-positions). Only completed unwinds are returned — pending or reverted unwinds are excluded.

```json
{
  "data": [
    {
      "id": "dm_pos_abc123",
      "...": "...",
      "unwinds": {
        "current_leverage_bps": 30000,
        "origination_leverage_bps": 60000,
        "originated_at": "2025-06-01T12:00:00.000Z",
        "data": [
          {
            "executed_at": "2025-06-02T14:30:00.000Z",
            "before_leverage_bps": 60000,
            "after_leverage_bps": 30000,
            "reason": "spread_blowout",
            "reason_detail": "The bid-ask spread widened sharply beyond its recent baseline, signalling thinning liquidity."
          }
        ],
        "has_more": false
      }
    }
  ],
  "has_more": true
}
```

**Field reference (each unwind event):**

| Field                 | Type    | Description                                                                                                                                                                                                                     |
| --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `after_leverage_bps`  | integer | Leverage after unwind in basis points (20000 = 2x)                                                                                                                                                                              |
| `before_leverage_bps` | integer | Leverage before unwind in basis points (20000 = 2x)                                                                                                                                                                             |
| `executed_at`         | string  | ISO 8601 timestamp when the unwind was executed on-chain                                                                                                                                                                        |
| `reason`              | string  | Machine-readable code for the market signal that triggered the risk model to deleverage this position. `null` for unwinds not tied to a risk-model run (e.g. manual admin deleveraging). See the reason reference below.        |
| `reason_detail`       | string  | Human-readable, customer-facing sentence explaining `reason` (e.g. "The bid-ask spread widened sharply beyond its recent baseline, signalling thinning liquidity."). Display this directly; `null` whenever `reason` is `null`. |

**`reason` values:**

| Value                   | Meaning                                                                                       |
| ----------------------- | --------------------------------------------------------------------------------------------- |
| `spread_blowout`        | The bid-ask spread widened sharply beyond its recent baseline, signalling thinning liquidity. |
| `spread_spike`          | The bid-ask spread jumped abruptly to several times its baseline.                             |
| `spread_warning`        | The bid-ask spread widened past an elevated warning level.                                    |
| `depth_decay`           | Resting order-book depth fell well below its recent peak.                                     |
| `depth_drain`           | Order-book depth across the market dropped sharply from entry levels.                         |
| `depth_entry_drain`     | Order-book depth fell far below the level present when the position opened.                   |
| `price_drop_warning`    | The position's side ticked down — an early adverse-price signal.                              |
| `price_drop_moderate`   | The position's side fell moderately against the position.                                     |
| `price_drop_severe`     | The position's side fell sharply against the position.                                        |
| `price_drop_full_exit`  | The position's side dropped far enough to fully deleverage rather than step down.             |
| `activity_surge`        | A surge in trading activity signalled elevated volatility.                                    |
| `cancel_acceleration`   | A spike in order cancellations signalled market makers pulling liquidity.                     |
| `large_holder`          | A large holder entered or materially grew their position in this market.                      |
| `position_exposure`     | The position grew large relative to available exit liquidity.                                 |
| `last_trade_divergence` | The last traded price diverged materially from the current bid.                               |
| `crypto_move`           | The underlying crypto price moved beyond its risk threshold.                                  |
| `game_start`            | The underlying game went live.                                                                |
| `lead_change`           | The lead changed in the underlying game.                                                      |
| `post_hard_exit_losing` | Risk was re-evaluated after a hard-exit event on the losing side.                             |
| `stale_refresh`         | A scheduled periodic risk refresh, not triggered by a specific market event.                  |
| `unknown`               | The position was deleveraged by the risk engine; the specific signal was not attributed.      |

The first unwind's `before_leverage_bps` equals the position's entry leverage. Each subsequent unwind's `before_leverage_bps` equals the previous unwind's `after_leverage_bps`.

***

### Position transactions (sub-resource)

Returns every on-chain transaction tied to a position, grouped by operation type, so you can give users full visibility into the on-chain transfers behind their position. Each group is an object with a `transactions` array; transactions that route through an exchange (open, close, liquidation, settle, force\_unwind) also include the on-chain hashes of their nested exchange (CLOB/DEX) fills. Only transactions that landed and finalized on-chain are returned — pending, failed, and reverted transactions are excluded.

```
GET /prediction-markets/positions/{position_id}/transactions
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const transactions = await client.getPositionTransactions(positionId);
```

**Auth:** User JWT — must belong to the JWT's `(wallet_address, partner_id)`.

**Response: `200 OK`**

```json
{
  "open": {
    "transactions": [
      {
        "transaction_hash": "0xffe5e3d042e9bf100fd01ad7a8d4de5d7fd20632df62e319d50275673e42e410",
        "exchange_transaction_hashes": [
          "0xddc31a8f7d2e4c0b9a1e5f3c8b6d4a2e0f9c7b5a3d1e8f6c4b2a0d9e7f5c3b1a"
        ]
      },
      {
        "transaction_hash": "0xaa11bb22cc33dd44ee55ff6677889900aabbccddeeff00112233445566778899"
      }
    ]
  },
  "close": {
    "transactions": []
  },
  "liquidation": {
    "transactions": []
  },
  "settle": {
    "transactions": []
  },
  "force_unwind": {
    "transactions": []
  },
  "cancel_request": {
    "transactions": []
  },
  "cancel": {
    "transactions": []
  },
  "revert": {
    "transactions": []
  },
  "redemption": {
    "transactions": []
  }
}
```

Each group is an object with a `transactions` array (wrapped in an object so the response can carry per-group metadata in the future without a breaking change).

**Field reference:**

| Field            | Type   | Description                                                                                            |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------ |
| `cancel`         | object | Transactions that cancelled the position before it opened.                                             |
| `cancel_request` | object | The close request transaction the position owner submitted on-chain.                                   |
| `close`          | object | Transactions that closed the position, including the finalize-close transaction.                       |
| `force_unwind`   | object | Transactions that force-unwound (deleveraged) the position, including the finalize-unwind transaction. |
| `liquidation`    | object | Transactions that liquidated the position, including the finalize-liquidation transaction.             |
| `open`           | object | Transactions that opened the position, including the finalize-open transaction.                        |
| `redemption`     | object | Transactions that redeemed settled position tokens.                                                    |
| `revert`         | object | Transactions that reverted a failed open back to the protocol.                                         |
| `settle`         | object | Transactions that settled the position, including the finalize-settle transaction.                     |

Every group object has a single `transactions` field (`object[]`) holding the entries below.

**Each transaction object:**

| Field                         | Type      | Description                                                                                             |
| ----------------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
| `exchange_transaction_hashes` | string\[] | On-chain hashes of the nested exchange (CLOB/DEX) fills. Present only for exchange-routed transactions. |
| `transaction_hash`            | string    | On-chain transaction hash (EVM transaction hash or Solana signature).                                   |

**Errors:**

| Status | Code                                       |
| ------ | ------------------------------------------ |
| 404    | `customer_position_transactions_not_found` |

***

### Position partial closes (sub-resource)

Returns the executed partial-close history for a position, in chronological order — one entry per partial close, with the tokens sold, the average realized sale price, the proceeds, the protocol capital repaid, the owner payout, and the size and leverage left afterwards. Only partial closes that finalized on-chain are returned — pending and reverted partial closes are excluded.

```
GET /prediction-markets/positions/{position_id}/partial-closes
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const partialCloses = await client.getPositionPartialCloses(positionId);
```

**Auth:** User JWT — must belong to the JWT's `(wallet_address, partner_id)`.

**Response: `200 OK`**

```json
{
  "data": [
    {
      "executed_at": "2026-07-01T14:59:28.000Z",
      "sold_token_units": "94590000",
      "average_sale_price_usd_pips": "2838",
      "average_sale_price_usd": "0.28",
      "sale_proceeds_usd_pips": "268468",
      "sale_proceeds_usd": "26.85",
      "capital_repaid_usd_pips": "144859",
      "capital_repaid_usd": "14.49",
      "user_payout_usd_pips": "123608",
      "user_payout_usd": "12.36",
      "remaining_position_token_units": "220720000",
      "new_leverage_bps": 19999
    }
  ],
  "has_more": false
}
```

**Field reference (each entry in `data`):**

| Field                            | Type           | Description                                                                           |
| -------------------------------- | -------------- | ------------------------------------------------------------------------------------- |
| `executed_at`                    | string         | ISO 8601 timestamp when the partial close settled on-chain.                           |
| `sold_token_units`               | string         | Token units sold in this partial close (1,000,000 units = 1 token).                   |
| `average_sale_price_*`           | string         | Average realized sale price for the sold slice (net of venue fee).                    |
| `sale_proceeds_*`                | string         | Gross sale proceeds received for the sold slice.                                      |
| `capital_repaid_*`               | string         | Protocol capital repaid from the proceeds.                                            |
| `user_payout_*`                  | string         | Amount paid out to the position owner from the proceeds.                              |
| `remaining_position_token_units` | string         | Position token units still held after this partial close.                             |
| `new_leverage_bps`               | number or null | Book leverage after this partial close (20000 = 2x). `null` if not recorded on-chain. |

**Errors:**

| Status | Code                          |
| ------ | ----------------------------- |
| 404    | `customer_position_not_found` |

***

## 5. Limits

### Partner limits

Partner's global position limit and current usage.

```
GET /prediction-markets/partner-limits
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const limits = await client.getPartnerLimits();
```

**Auth:** Partner API key

**Response: `200 OK`**

```json
{
  "limit_usd_pips": "5000000000",
  "limit_usd": "500000.00",
  "usage_usd_pips": "1200000000",
  "usage_usd": "120000.00",
  "remaining_usd_pips": "3800000000",
  "remaining_usd": "380000.00"
}
```

### User limits

Position limits for the authenticated user.

```
GET /prediction-markets/user-limits
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const limits = await client.getUserLimits();
```

**Auth:** User JWT

**Response: `200 OK`**

```json
{
  "limit_usd_pips": "100000000",
  "limit_usd": "10000.00",
  "usage_usd_pips": "25000000",
  "usage_usd": "2500.00",
  "remaining_usd_pips": "75000000",
  "remaining_usd": "7500.00"
}
```

| Field             | Description                                        |
| ----------------- | -------------------------------------------------- |
| `limit_usd_*`     | Maximum total notional across all open positions   |
| `remaining_usd_*` | `limit - usage`                                    |
| `usage_usd_*`     | Sum of origination notional for all open positions |

***

## 6. Fees

These endpoints let you reproduce a quote's economics client-side — the fee schedule, and a full pre-quote cost/profit breakdown — without creating a quote.

### Fee rates

The protocol fee schedule plus your partner's fee components. Pass `ticker` to also include that market's venue ( Polymarket) fee fields.

```
GET /prediction-markets/fee-rates
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const feeRates = await client.getFeeRates({ ticker: "will-btc-hit-100k-2025" });
```

**Auth:** User JWT

**Query parameters:**

| Parameter | Required | Description                                              |
| --------- | -------- | -------------------------------------------------------- |
| `ticker`  | No       | Market ticker. When set, the response includes `market`. |

**Response: `200 OK`**

```json
{
  "contract_max_origination_fee_bps": 1000,
  "lifetime_fee_apr_bps": 2000,
  "liquidation_fee_bps": 250,
  "origination_fee_tiers": [
    {
      "fee_bps": 200,
      "max_leverage_bps": 40000
    },
    {
      "fee_bps": 225,
      "max_leverage_bps": 70000
    },
    {
      "fee_bps": 250,
      "max_leverage_bps": 100000
    }
  ],
  "partner_origination_fee_bps": 0,
  "partner_trading_fee_bps": 0,
  "market": {
    "polymarket_fee_exponent": 1,
    "polymarket_trading_fee_bps": 0,
    "ticker": "TRUMP-2024-WIN"
  }
}
```

| Field                              | Description                                                                                                  |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `origination_fee_tiers`            | Leverage-tiered protocol origination fee. Pick the first tier whose `max_leverage_bps >= leverage_bps`.      |
| `contract_max_origination_fee_bps` | On-chain cap on the combined (protocol + partner) origination fee.                                           |
| `lifetime_fee_apr_bps`             | Lifetime fee APR, charged on protocol capital over time.                                                     |
| `liquidation_fee_bps`              | Liquidation fee, on protocol capital.                                                                        |
| `partner_origination_fee_bps`      | Your origination fee component, added on top of the protocol tier. *(deprecated — prefer builder code fees)* |
| `partner_trading_fee_bps`          | Your Polymarket builder taker fee (flat % of notional).                                                      |
| `market`                           | Per-market venue fee fields. Only present when `ticker` is supplied.                                         |

### Fee report

A full cost and max-gain breakdown for a hypothetical position, computed from notional + leverage using the market's fee rates. Does **not** create a quote and does not sign anything. The liquidation price is a deterministic at-entry estimate; the binding quote uses a TWAP/inference-based price that may differ.

```
POST /prediction-markets/fee-reports
```

**SDK** ([`@dimes-dot-fi/sdk`](/for-developers/getting-started/sdk-installation.md)):

```typescript
const report = await client.getFeeReport({ /* FeeReportParams: date range + filters */ });
```

**Auth:** User JWT

**Request body:**

| Field                      | Required | Description                                                                                         |
| -------------------------- | -------- | --------------------------------------------------------------------------------------------------- |
| `market_ticker`            | Yes      | Market ticker.                                                                                      |
| `effective_side`           | Yes      | `yes` or `no`.                                                                                      |
| `leverage_bps`             | Yes      | Leverage in basis points (20000 = 2x).                                                              |
| `notional_amount_usd_pips` | Yes      | Notional in USD pips.                                                                               |
| `entry_price_usd_pips`     | No       | Effective-side entry price in USD pips. When omitted, the market's current reference price is used. |

**Response: `200 OK`**

```json
{
  "collateral_usdc_units": "25000000",
  "effective_side": "yes",
  "entry_price_usd_pips": "5100",
  "estimated_liquidation_price_usd_pips": "2613",
  "expected_open_trading_fee_usdc_units": "0",
  "gross_max_gain_usdc_units": "48039215",
  "leverage_bps": 20000,
  "market_ticker": "TRUMP-2024-WIN",
  "net_max_gain_usdc_units": "47039215",
  "notional_amount_usd_pips": "500000",
  "notional_usdc_units": "50000000",
  "origination_fee_bps": 200,
  "origination_fee_usdc_units": "1000000",
  "partner_origination_fee_bps": 0,
  "partner_trading_fee_bps": 0,
  "polymarket_trading_fee_bps": 0,
  "protocol_origination_fee_bps": 200,
  "total_user_amount_usdc_units": "26000000"
}
```

| Field                                  | Description                                                                                                             |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `estimated_liquidation_price_usd_pips` | At-entry liquidation price estimate: `entry * (L-1)/L * (1 + liquidation_fee_bps/10000)`. Estimate only.                |
| `expected_open_trading_fee_usdc_units` | Venue trading fee to open (protocol venue fee + partner builder fee).                                                   |
| `gross_max_gain_usdc_units`            | Profit on a win (settlement at $1) before fees: full token value minus notional. May be negative.                       |
| `net_max_gain_usdc_units`              | `gross_max_gain` minus the open trading fee and origination fee. Excludes lifetime fees (upper bound). May be negative. |
| `origination_fee_*`                    | Combined origination fee (protocol tier + partner) at this leverage.                                                    |
| `total_user_amount_usdc_units`         | Total the user must provide to open: collateral + open trading fee + origination fee.                                   |

***

## Endpoint Summary

| Method | Path                                                          | Auth                | Description            |
| ------ | ------------------------------------------------------------- | ------------------- | ---------------------- |
| `GET`  | `/v1/prediction-markets/markets`                              | User JWT or API key | List/search markets    |
| `GET`  | `/v1/prediction-markets/markets/{ticker}`                     | User JWT or API key | Get market by ticker   |
| `GET`  | `/v1/prediction-markets/contract-info`                        | Public              | Contract verification  |
| `POST` | `/v1/prediction-markets/tokens`                               | Partner API key     | Generate user JWT      |
| `POST` | `/v1/prediction-markets/quotes`                               | User JWT            | Create quote           |
| `POST` | `/v1/prediction-markets/draft-quotes`                         | User JWT            | Create draft quote     |
| `POST` | `/v1/prediction-markets/promoted-quotes/{id}`                 | User JWT            | Promote draft to quote |
| `GET`  | `/v1/prediction-markets/positions`                            | User JWT            | List positions         |
| `GET`  | `/v1/prediction-markets/positions/{position_id}`              | User JWT            | Get position           |
| `GET`  | `/v1/prediction-markets/positions/{position_id}/transactions` | User JWT            | Position transactions  |
| `GET`  | `/v1/prediction-markets/partner-limits`                       | Partner API key     | Partner limits         |
| `GET`  | `/v1/prediction-markets/user-limits`                          | User JWT            | User limits            |
| `GET`  | `/v1/prediction-markets/fee-rates`                            | User JWT            | Fee schedule           |
| `POST` | `/v1/prediction-markets/fee-reports`                          | User JWT            | Cost & max-gain report |

***

## Throttling

All endpoints are rate-limited. The throttling scope and limit depend on authentication:

| Auth type       | Scope          | Limit              |
| --------------- | -------------- | ------------------ |
| API key         | Per partner    | 120 requests / min |
| JWT             | Per wallet     | 60 requests / min  |
| Unauthenticated | Per IP address | 30 requests / min  |

**Exception:** The `POST /v1/prediction-markets/tokens` endpoint (JWT generation) is throttled at **1800 requests per minute** per partner.

### Rate limit headers

Every response includes:

| Header                  | Description                                    |
| ----------------------- | ---------------------------------------------- |
| `X-RateLimit-Limit`     | Maximum requests allowed in the current window |
| `X-RateLimit-Remaining` | Requests remaining in the current window       |
| `X-RateLimit-Reset`     | Seconds until the current window resets        |

When throttled, the response also includes a `Retry-After` header with the number of seconds to wait before retrying.

**`429 Too Many Requests`**

```json
{
  "error": {
    "type": "RATE_LIMIT_ERROR",
    "code": "too many requests",
    "message": "Too Many Requests"
  }
}
```
