---
title: "Read-only spot market quote (price, cost, affordability)"
method: POST
path: "/api/agent/spot/quote"
tags: ["spot"]
---

# Read-only spot market quote (price, cost, affordability)

`POST /api/agent/spot/quote`

## Request

- Base URL: `https://api.coinrithm.com`
- URL: `https://api.coinrithm.com/api/agent/spot/quote`
- Auth: HTTP bearer

Never mutates state. Returns the live execution price, estimated cost
(price × quantity), your available balance, and whether the fill is
`eligible` — quote BEFORE `spot/order` instead of buying blind. Price
age is informational `freshness`. Optional `priceTiming` adds the
venue's own snapshot time next to CoinRithm's write time; it is
informational only: `freshness`, `eligible`/`blockReasons` and the
order path's guards still measure the row write time and are
unchanged. Requires scope `read`.

## Request body

- SpotQuoteRequest
  - `coinId` string, required: Coin UCID (e.g. "1" = BTC). NOT a ticker symbol.
  - `side` 'buy' | 'sell', required
  - `quantity` number, required: Amount of the base coin (> 0).
  - `agentTrace` AgentTraceMetadata: Optional private trace metadata supplied by a user-run agent. CoinRithm stores only this structured summary; do not send chain-of-thought, secrets, emails, or private account identity.
    - `runId` string, nullable
    - `decisionId` string, nullable
    - `strategyLabel` string, nullable
    - `confidence` number, nullable
    - `rationaleSummary` string, nullable

## Response `200`

OK

- SpotQuoteResponse
  - `eligible` boolean
  - `blockReasons` string[]: e.g. price_unavailable, insufficient_usdt_balance, insufficient_coin_balance, wallet_not_found.
  - `coin` object
    - `ucid` string
    - `symbol` string
    - `name` string
  - `side` 'buy' | 'sell'
  - `quantity` number
  - `orderType` 'market'
  - `executionPrice` number, nullable: Estimated fill price — live mid adjusted for spread+slippage; null when unavailable.
  - `estimatedCostMusd` number, nullable: Gross notional (price × quantity). BUY = cash debited; SELL = proceeds.
  - `estimatedFeeMusd` number, nullable: Estimated taker fee for this trade (mUSD), included in the affordability check.
  - `executionModel` ExecutionModel: Paper Execution Realism v1 cost disclosure. Paper fills apply a deterministic, fully-disclosed cost so simulated PnL reflects real trading friction (a flat round-trip is a small loss, not a free breakeven). This is a rehearsal cost model, NOT an exchange fill guarantee. Per venue: - spot: a taker fee (`feeBps`) on notional, with market orders also filling at an adverse price (half-spread + slippage). Futures use the default-off legacy mark fill unless `futures_fill_v1` is pinned; that model applies deterministic half-spread, slippage, and square-root size-scaled impact, with adverse cost embedded in the executed price. - PM: fills at the ask (mid + half the ingested bid-ask spread) with size/liquidity-based slippage and a Polymarket-shaped taker fee (~1.8% near 50%, ~0 at the extremes), folded into `sharesMusd`. `feeBps`/`spreadBps` are positive and `slippageBps` scales with order size; `entryProbability` stays the mid for calibration. Futures quote funding is estimated from the latest venue rate when available and may change before settlement. Covered futures charges are applied from recorded settled venue history; `fundingMode` is a venue-specific mode such as `binance_perp_rate_v1`, `bybit_perp_rate_v1`, or `gateio_perp_rate_v1`, and is `not_modeled` when no latest rate is available. Funding does not apply to spot or PM. Futures liquidation forfeits margin without adverse fill cost, and fixed-price SL/TP triggers fill at their set price. Order-book depth, latency, and partial fills are not modeled.
    - `version` string
    - `feeBps` number: taker fee, basis points of notional
    - `spreadBps` number: modeled bid/ask spread (bps)
    - `slippageBps` number: modeled slippage (bps)
    - `fillModel` string, nullable: Futures fill model pinned for this execution, or null for legacy mark fills.
    - `estimatedFeeMusd` number: estimated fee for this trade (mUSD)
    - `estimatedSlippageMusd` number: estimated slippage cost for this trade (mUSD)
    - `fundingMode` string: Venue-specific current funding reference mode, or not_modeled when no latest rate is available.
    - `assumptions` string[]: human-readable list of what is and isn't modeled
  - `available` object
    - `usdtAvailableMusd` number: spendable cash for a BUY
    - `coinAvailable` number: coin units held for a SELL
  - `freshness` Freshness: Data-freshness descriptor. Futures + spot use ageSeconds; PM uses ageMinutes. `status` is a freshness label; `basis` (PM only) names which timestamp the age was measured against.
    - `asOf` string, date-time, nullable
    - `ageSeconds` number, nullable: futures / spot
    - `ageMinutes` number, nullable: PM
    - `status` 'fresh' | 'lagging' | 'stale' | 'unknown' | 'null', nullable: fresh | lagging (PM only) | stale | unknown. PM lagging>=45m & stale>=2h; spot/futures stale>120s.
    - `basis` 'latest_snapshot' | 'source_update' | 'processed' | 'event_update' | 'unknown', nullable: PM only — which timestamp the age was measured against.
  - `priceTiming` SpotPriceTiming: Source-vs-row timing of the spot price (optional: absent on older API versions). Informational only: `freshness`, `eligible` and the write path's mark guard still measure the row WRITE time and are unchanged. `sourceObservedAt` is a venue snapshot/ticker time, NOT a last-trade time and NOT a per-fill receipt.
    - `rowWrittenAt` string, date-time, nullable, required: When CoinRithm wrote the price row; the same instant as freshness.asOf. null when there is no row.
    - `sourceObservedAt` string, date-time, nullable, required: The OLDEST venue snapshot time among the winning price cluster's members that carry one. null when no member carries one.
    - `sourceAgeSeconds` number, nullable, required: max(0, now - sourceObservedAt), the same clamp as freshness.ageSeconds.
    - `writeLagSeconds` number, nullable, required: rowWrittenAt - sourceObservedAt in seconds, SIGNED. Negative means the venue's clock ran ahead of CoinRithm's (the writer admits up to 5 minutes); it is never clamped.
    - `coverage` 'recorded' | 'not_recorded' | 'no_row', required: recorded: at least one cluster member carried a source time. It may be PARTIAL: members without a stamp (e.g. Kraken, Gate.io) are not represented. not_recorded: the row has no source time (unknown, never fresh). no_row: there is no price row.
    - `basis` 'venue_snapshot_time', required
  - `asOf` string, date-time
  - `observation` AgentObservation: Compact provenance block for an agent-facing market observation. It is also stored in the private ledger responseSummary when the request uses agentTrace/run headers, giving run exports a verifiable snapshot of what the agent observed without creating a full market archive.
    - `schema` string
    - `endpoint` string
    - `source` string
    - `observedAt` string, date-time
    - `sourceAsOf` string, date-time, nullable
    - `freshness` Freshness: Data-freshness descriptor. Futures + spot use ageSeconds; PM uses ageMinutes. `status` is a freshness label; `basis` (PM only) names which timestamp the age was measured against.
      - `asOf` string, date-time, nullable
      - `ageSeconds` number, nullable: futures / spot
      - `ageMinutes` number, nullable: PM
      - `status` 'fresh' | 'lagging' | 'stale' | 'unknown' | 'null', nullable: fresh | lagging (PM only) | stale | unknown. PM lagging>=45m & stale>=2h; spot/futures stale>120s.
      - `basis` 'latest_snapshot' | 'source_update' | 'processed' | 'event_update' | 'unknown', nullable: PM only — which timestamp the age was measured against.
    - `inputs` object
    - `dataset` object
    - `rowCount` integer, nullable
    - `hash` string: Short SHA-256 digest of the observed payload metadata.

## Other responses

- `400`: Invalid or missing parameters. On a route with a query allowlist, an undocumented query parameter returns `{"error": "unsupported_query_parameter", "message": "Unsupported query parameter: <key>. Supported: <keys>."}`.
- `401`: Missing/malformed or invalid/revoked API key
- `403`: API key missing the required scope
- `404`: Coin not found
- `429`: Rate limit exceeded for this API key (120 req/min baseline, 20 trade-writes/min). Honor `Retry-After`, then resume; the `RateLimit-*` headers on every response let you pace proactively. (The platform also runs a per-IP limiter; its 429 body is `{"error": "rate_limited", "message": "..."}`.)

---

[API](https://skmtc.dev/coinrithm/apis/coinrithm-agent-trading-api.md) · [All operations](https://skmtc.dev/coinrithm/apis/coinrithm-agent-trading-api/llms.txt) · [OpenAPI document](https://skmtc.dev/coinrithm/apis/coinrithm-agent-trading-api/revisions/28fb59f285fe?raw)
