/api/v1/portfolio
Quotient intelligence for a wallet's portfolio across venues
Returns wallet positions joined to the latest forecast, published signal, and calculations using the position's own side. Omitting venues returns the legacy Polymarket shape; include_perps=true adds Polymarket perps. Legacy Polymarket upstream failures return 502 upstream_unavailable. Passing venues returns separate polymarket, polymarket_perps, limitless, and hyperliquid results with per-venue wallets, positions, and availability status. Each venue returns its complete fetched positions or status=unavailable. Kalshi and Polymarket US currently lack a keyless wallet-addressed positions API.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| wallet | query | string | Wallet address used for every requested venue. Required unless a per-venue wallet is supplied for each one. For Polymarket this is the proxy wallet. Pattern: ^0x[0-9a-fA-F]{40}$ |
| venues | query | string | Comma-separated venues for the multi-venue report: polymarket, polymarket_perps, limitless, hyperliquid, or all. Omit for the legacy Polymarket-only response. |
| polymarket_wallet | query | string | Overrides wallet for Polymarket only (proxy wallet). Pattern: ^0x[0-9a-fA-F]{40}$ |
| polymarket_perps_wallet | query | string | Overrides wallet for Polymarket perps only. Pattern: ^0x[0-9a-fA-F]{40}$ |
| limitless_wallet | query | string | Overrides wallet for Limitless only. Pattern: ^0x[0-9a-fA-F]{40}$ |
| hyperliquid_wallet | query | string | Overrides wallet for Hyperliquid only (the trading EOA). Pattern: ^0x[0-9a-fA-F]{40}$ |
| size_threshold | query | number | Minimum position size to include (passed to the Polymarket data API) Default: 1; Minimum: 0 |
| include_perps | query | boolean | Legacy mode only: annex Polymarket perps positions. In multi-venue mode request the polymarket_perps venue instead. Default: false |
Responses
200: Positions joined to Quotient coverage. Legacy shape without `venues`; the multi-venue envelope with it.
| Field | Type | Description | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Alternative 1 | PortfolioResponse | Exactly one alternative Alternative 1 fields
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Alternative 2 | MultiVenuePortfolioResponse | Returned when `venues` is supplied. Each venue degrades independently: an unavailable venue is reported as status=unavailable inside a 200 within the multi-venue report. Exactly one alternative Alternative 2 fields
|
401: Unauthorized
| Field | Type | Description |
|---|---|---|
| error required | string | Error code |
| message required | string | Human-readable message |
| retry_after | integer | Seconds to wait (only on 429) |
| retryAfter | integer | Seconds to wait for owner-scoped forecast-request quota errors. |
| limit_scope | string | Quota scope that rejected the request, such as standard or x_research. |
| quotaScope | string | Stable forecast-request quota scope, such as venue_market_daily. |
| limit | integer | Configured bound for the forecast-request quota that was exceeded. |
402: Payment Required
| Field | Type | Description |
|---|---|---|
| error required | string | Error code |
| message required | string | Human-readable message |
| retry_after | integer | Seconds to wait (only on 429) |
| retryAfter | integer | Seconds to wait for owner-scoped forecast-request quota errors. |
| limit_scope | string | Quota scope that rejected the request, such as standard or x_research. |
| quotaScope | string | Stable forecast-request quota scope, such as venue_market_daily. |
| limit | integer | Configured bound for the forecast-request quota that was exceeded. |
403: Insufficient credits for the requested route
| Field | Type | Description |
|---|---|---|
| error required | string | Error code |
| message required | string | Human-readable message |
| retry_after | integer | Seconds to wait (only on 429) |
| retryAfter | integer | Seconds to wait for owner-scoped forecast-request quota errors. |
| limit_scope | string | Quota scope that rejected the request, such as standard or x_research. |
| quotaScope | string | Stable forecast-request quota scope, such as venue_market_daily. |
| limit | integer | Configured bound for the forecast-request quota that was exceeded. |
422: Invalid request parameters (wallet must be a 0x address; venues must name supported venues)
| Field | Type | Description |
|---|---|---|
| error required | string | Error code |
| message required | string | Human-readable message |
| retry_after | integer | Seconds to wait (only on 429) |
| retryAfter | integer | Seconds to wait for owner-scoped forecast-request quota errors. |
| limit_scope | string | Quota scope that rejected the request, such as standard or x_research. |
| quotaScope | string | Stable forecast-request quota scope, such as venue_market_daily. |
| limit | integer | Configured bound for the forecast-request quota that was exceeded. |
429: The caller exceeded a per-second, per-minute, daily, or concurrency limit. No credits are debited and no x402 payment is settled for this response.
| Field | Type | Description |
|---|---|---|
| error required | string | Error code |
| message required | string | Human-readable message |
| retry_after | integer | Seconds to wait (only on 429) |
| retryAfter | integer | Seconds to wait for owner-scoped forecast-request quota errors. |
| limit_scope | string | Quota scope that rejected the request, such as standard or x_research. |
| quotaScope | string | Stable forecast-request quota scope, such as venue_market_daily. |
| limit | integer | Configured bound for the forecast-request quota that was exceeded. |
502: Legacy mode only: Polymarket data API unavailable (upstream_unavailable). In multi-venue mode an unavailable venue is reported as status=unavailable inside a 200.
| Field | Type | Description |
|---|---|---|
| error required | string | Error code |
| message required | string | Human-readable message |
| retry_after | integer | Seconds to wait (only on 429) |
| retryAfter | integer | Seconds to wait for owner-scoped forecast-request quota errors. |
| limit_scope | string | Quota scope that rejected the request, such as standard or x_research. |
| quotaScope | string | Stable forecast-request quota scope, such as venue_market_daily. |
| limit | integer | Configured bound for the forecast-request quota that was exceeded. |
Set QUOTIENT_API_KEY in your shell and replace example identifiers with returned IDs before running a request.
curl --request GET \
--header "x-quotient-api-key: $QUOTIENT_API_KEY" \
'https://quotient-api-gateway.onrender.com/api/v1/portfolio'{
"wallet": "example",
"as_of": "2027-01-01T00:00:00Z",
"value_usd": 0,
"positions_count": 0,
"covered_count": 0,
"unmatched_count": 0,
"positions_capped": false,
"positions": [
{
"condition_id": "example",
"title": "example",
"slug": "example",
"event_slug": "example",
"outcome": "example",
"size": 0,
"avg_price": 0,
"cur_price": 0,
"current_value_usd": 0,
"cash_pnl": 0,
"percent_pnl": 0,
"redeemable": false,
"end_date": "example",
"quotient": {
"covered": false,
"market": {
"venue": null,
"nativeMarketId": null,
"nativeEventId": null,
"seriesTicker": null,
"marketKey": null,
"quotientMarketId": null,
"slug": null,
"marketUrl": null,
"sourceUrl": null,
"broker_channels": null,
"robinhood_category": null,
"robinhood_url": null,
"question": null,
"quotientUrl": null,
"polymarketUrl": null,
"relationships": null
},
"forecast": {
"venue": "polymarket",
"market": {
"venue": null,
"nativeMarketId": null,
"nativeEventId": null,
"seriesTicker": null,
"marketKey": null,
"quotientMarketId": null,
"slug": null,
"marketUrl": null,
"sourceUrl": null,
"broker_channels": null,
"robinhood_category": null,
"robinhood_url": null
},
"id": "example",
"probability": 0,
"created_at": "2027-01-01T00:00:00Z",
"delta_from_prior": 0,
"refresh_reason": "example",
"bluf": "example",
"thesis": "example",
"resolution_pathway": {
"criteria": null,
"crux": null,
"deadline": null,
"source": null
},
"conviction_tier": 0,
"relationships": {
"assets": null,
"markets": null,
"signals": null,
"truncated": null
}
},
"signal": {
"id": "example",
"side": "YES",
"created_at": "2027-01-01T00:00:00Z",
"is_active": false,
"retired_reason": "resolved",
"relationships": {
"assets": null,
"markets": null,
"signals": null,
"truncated": null
}
},
"forecast_status": {
"state": null,
"cents": null,
"adverse_move_pct": null,
"basis": null,
"price_source": null
},
"convergence": {
"aligned": false,
"q_side": "YES",
"q_value_cents": 0,
"entry_cost_cents": 0,
"current_cost_cents": 0,
"distance_to_convergence_cents": 0,
"converge_upside_pct": 0,
"max_roi_pct": 0,
"priced_at": "2027-01-01T00:00:00Z"
}
}
}
],
"unmatched": [
{
"condition_id": "example",
"title": "example",
"slug": "example"
}
],
"perps": {
"positions": [
{
"symbol": "example",
"size": 0,
"entry_price": 0,
"unrealized_pnl": 0,
"return_on_equity": 0
}
],
"equity": 0,
"error": "example"
}
}