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

# Submit or Replace Quote

> Submit a price quote for an active quote request, or replace your existing quote.

Submit a quote for an active quote request. If you already have an active quote for the same request version, it is replaced atomically. Only one active quote per market maker per request version is allowed.

When the user updates their request (changing legs or bet amount), the `version` and `request_hash` change, and your existing quote is automatically invalidated. Listen for `quote_request:updated` events on the [SSE stream](/api-reference/quote-service-mm/stream) to detect version changes and re-price.

<Note>
  **Moving to a new version needs no withdraw.** A quote is scoped to a single `(request, version)` pair. When the request advances to a new `version`, your prior version quote is invalidated automatically — it leaves the book at once, can no longer be accepted, and never blocks a new submission. To quote the new version, `PUT` again with the new `request_version` and `request_hash` from the latest `quote_request:updated` event. You don't need to [withdraw](/api-reference/quote-service-mm/withdraw-quote) the old quote first.

  A `409` with `reason: version_mismatch` is **not** caused by an outstanding prior quote. It means the `request_version` and/or `request_hash` in your body no longer match the live request — you priced a stale version, or the slip changed again while you were pricing. Re-read the latest stream event and submit with both current values (they must both match).
</Note>

## Authentication

API key required. Pass your market maker API key in the `X-API-Key` header.

```
X-API-Key: <key>
```

## Path parameters

<ParamField path="id" type="string" required>
  The quote request ID (UUID).
</ParamField>

## Request body

<ParamField body="request_version" type="integer" required>
  The version of the quote request you priced. Must match the current version from the SSE stream.
</ParamField>

<ParamField body="request_hash" type="string" required>
  The `request_hash` from the quote request event. Prevents pricing against stale data.
</ParamField>

<ParamField body="payout_odds" type="number" required>
  Payout multiplier on the user's bet amount. Between 1.0001 and 1000. The server derives all cost fields (`user_cost`, `total_payout`, `mm_cost`) from this value and the request's `bet_amount`.
</ParamField>

<ParamField body="expires_in_ms" type="integer">
  How long this quote is valid, in milliseconds. Range: 5000-60000. Default: 15000.
</ParamField>

## Response

Returns `201 Created` for a new quote or `200 OK` when replacing an existing quote.

<ResponseField name="data" type="object">
  <Expandable title="data">
    <ResponseField name="quote" type="object">
      The submitted quote.

      <Expandable title="quote">
        <ResponseField name="id" type="string">Quote UUID.</ResponseField>
        <ResponseField name="market_maker_id" type="string">Your market maker ID.</ResponseField>
        <ResponseField name="request_version" type="integer">The request version this quote is for.</ResponseField>
        <ResponseField name="request_hash" type="string">The request hash this quote is for.</ResponseField>
        <ResponseField name="payout_odds" type="number">The payout multiplier.</ResponseField>
        <ResponseField name="user_cost" type="number">Cost to the user in USDC (server-derived from `bet_amount`).</ResponseField>
        <ResponseField name="total_payout" type="number">Total payout in USDC (server-derived from `bet_amount * payout_odds`).</ResponseField>
        <ResponseField name="mm_cost" type="number">Your risk in USDC (server-derived: `total_payout - user_cost`).</ResponseField>
        <ResponseField name="valid_until" type="string">ISO 8601 timestamp when this quote expires.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="book_seq" type="integer">The new quote book sequence number.</ResponseField>
    <ResponseField name="replaced" type="boolean">`true` if this replaced a previous quote.</ResponseField>
  </Expandable>
</ResponseField>

## Conflict reasons

When a submit is rejected with `409 Conflict`, the `error.details.reason` field explains why:

| Reason             | Description                                                                                                                                                                                                                                                                                                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `not_found`        | Quote request ID does not exist.                                                                                                                                                                                                                                                                                           |
| `expired`          | Quote request has expired.                                                                                                                                                                                                                                                                                                 |
| `not_active`       | Quote request is committed, cancelled, or otherwise inactive.                                                                                                                                                                                                                                                              |
| `version_mismatch` | Your `request_version` and/or `request_hash` don't match the live request — you priced a stale version, or it changed while you were pricing. Re-read the latest `quote_request` / `quote_request:updated` event and submit both current values. This is **not** caused by a still-open prior quote — nothing to withdraw. |
| `self_quote`       | You cannot quote your own requests.                                                                                                                                                                                                                                                                                        |

## Errors

| Status | Code               | Description                                 |
| ------ | ------------------ | ------------------------------------------- |
| 400    | `VALIDATION_ERROR` | Invalid body. See `details.issues`.         |
| 401    | `UNAUTHORIZED`     | Missing or invalid API key.                 |
| 409    | `CONFLICT`         | Quote rejected. See `details.reason` above. |

<RequestExample>
  ```bash theme={null}
  curl -X PUT https://api.totalis.trade/v1/mm/quote-requests/1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40/quote \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "request_version": 1,
      "request_hash": "sha256:9f86d08...",
      "payout_odds": 4.25,
      "expires_in_ms": 15000
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "data": {
      "quote": {
        "id": "b2c3d4e5-6789-0abc-def1-234567890abc",
        "market_maker_id": "mm-uuid-1234",
        "request_version": 1,
        "request_hash": "sha256:9f86d08...",
        "payout_odds": 4.25,
        "user_cost": 25,
        "total_payout": 106.25,
        "mm_cost": 81.25,
        "valid_until": "2026-06-01T18:45:45.000Z"
      },
      "book_seq": 5,
      "replaced": false
    }
  }
  ```
</ResponseExample>
