> For the complete documentation index, see [llms.txt](https://pred-1.gitbook.io/pred-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pred-1.gitbook.io/pred-docs/documentation/api-reference/market-discovery.md).

# Market Discovery

Market information and discovery (public; no auth). Use this section to understand **parent\_market\_id** and **market\_id** and to list all markets.

### What are parent\_market\_id and market\_id?

* **parent\_market\_id:** Identifies a parent market (e.g. a fixture or event). It groups one or more child markets. Order and orderbook paths are scoped by parent (e.g. `GET /api/v1/order/{parentMarketID}/orderbook/{marketID}`). Cancel and open-orders endpoints are also per parent.
* **market\_id:** Identifies a specific (child) market within a parent (e.g. one outcome: Team A, Team B, or Draw). Used in place order body (`market_id`), orderbook path (`marketID`), and cancel body. Each parent can have multiple child markets; each child has its own `market_id`.

You need both when placing orders (parent in the path, market\_id in the body) and when fetching orderbooks (parent and market in the path).

### Getting parent\_market\_id and market\_id

**Get all markets:** Call `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0`, then continue paging with `offset += limit` until all `data.total` rows are consumed. `verbose=true` is required for the trading-critical fields that non-verbose responses can omit: `parent_market_data.parent_market_id`, `parent_market_data.type_reference_id`, `parent_market_data.contract_address`, `parent_market_data.parent_market_type`, `parent_market_data.parent_market_family`, and fixture fields such as `fixture.fixture_id` and `fixture.game_start_time`. The response shape is `data.parent_markets_list[]`, where each entry has `parent_market_data`, optional `fixture`, optional `team_data`, and child `markets[]`.

### Discovering active markets

There is currently **no `active=true`, `active_only=true`, or `status=active` query filter** on `GET /api/v1/market-discovery/discover`. To reduce historical results, use:

```http
GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0&omit_inactive_with_redeemed_on_before=<CURRENT_UTC_TIMESTAMP>
```

Replace `<CURRENT_UTC_TIMESTAMP>` with a URL-encoded RFC3339 instant, for example `2026-09-09T12:00:00Z` (illustrative only; supply the current time when starting a scan). Keep that cutoff and the other filters unchanged while paging with `offset += limit`.

This is a **parent redemption-time filter, not an active-only filter**. It excludes parents with `redeemed_on` strictly before the cutoff, and parents with `status == "redeemed"` but no `redeemed_on`. Parents redeemed exactly at or after the cutoff can still appear. An unredeemed parent can also contain closed or resolved child markets.

For an active trading list, keep entries whose `parent_market_data.status == "active"`, then keep only their children where `markets[].status == "active"`; discard entries with no remaining children. Continue pagination even if a page has no active children: `data.total` describes the server-filtered parent feed, not the number of active children. Refresh the selected market's status before placing an order.

Do not use `start_time=<now>` as an active-status substitute: it filters fixture kickoff times and can exclude otherwise active markets. Likewise, `default=true` selects the default discovery flow rather than all active markets. Omit both when scanning the full discover-visible active set, unless you intentionally want their narrower scope.

**Fees:** discovery may include parent-level `parent_market_data.fee_rate_bps`. That value is the market's **target** fee-curve peak (basis points), **not** the value to sign on place-order. Compute the price-distorted signed rate (see **Orders → Fees**). The legacy SDK defaults a missing target to `0`; new integrations should stop and confirm missing configuration with PRED instead of assuming the market is fee-free. Explicit target `0` is valid.

**Runtime eligibility used by market-maker style clients:** first filter your own configured markets to `active`; then require the discovered parent row to have `parent_market_data.status == "active"`; then require the specific child row in `markets[]` to have `status == "active"`. Child statuses such as `resolved` or `redeemed` are terminal and should be treated as not quote/trade eligible. For market makers, also validate the PRED orderbook or external liquidity source for the child before enabling quoting.

**Important field mapping:** use `parent_market_data.parent_market_id` as the parent path parameter, `markets[].market_id` as the child `market_id`, `parent_market_data.type_reference_id` as the stable Ably orderbook channel key, `parent_market_data.contract_address` as the EIP-712 `verifyingContract`, `parent_market_data.parent_market_family` for family-level config, `parent_market_data.parent_market_type` to distinguish fixtures from generic/futures markets, and `fixture.game_start_time` for fixture/live-window logic.

To get details for a single parent (including its child market IDs and statuses), call `GET /api/v1/market-discovery/parents/{parentMarketID}`.

### Endpoints

* `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0` — paginated discovery feed for parent markets, child markets, contract addresses, market family/type, and fixture context.
* `GET /api/v1/market-discovery/parents/{parentMarketID}` — details for one parent, including child markets.

## Get market discovery feed

> Returns discovery entries with parent market data, fixture context, team data, and markets.\
> Trading clients should call this endpoint with \`verbose=true\` and paginate with \`limit\`/\`offset\`\
> until \`data.total\` is exhausted. Recommended page size for SDK/market-maker style clients is\
> \`limit=50\`; avoid bursts above roughly 10 discovery requests per second.\
> \
> \`verbose=true\` is required so \`parent\_market\_data.parent\_market\_id\`,\
> \`parent\_market\_data.contract\_address\`, \`parent\_market\_data.parent\_market\_type\`,\
> \`parent\_market\_data.parent\_market\_family\`, and fixture metadata are included reliably.\
> Non-verbose responses can omit these fields.\
> \
> Use \`data.parent\_markets\_list\[].parent\_market\_data.contract\_address\` as EIP-712\
> \`verifyingContract\` when signing place orders for that parent market.\
> \
> Status semantics:\
> \- parent \`parent\_market\_data.status\` typically remains \`active\` until the parent is fully redeemed; once redeemed it becomes \`redeemed\`.\
> \- child \`markets\[].status\` is the eligibility field to check for a specific market and can differ from the parent (for example, a parent may still be \`active\` while an individual child market is \`closed\`, \`resolved\`, or \`redeemed\`).\
> \
> Query/filter behavior:\
> \- no filter is required; default behavior returns all discover-visible parents as a paginated feed.\
> \- filter resolution precedence is \`default=true\`, then \`cname\`, then \`parent\_market\_type\`, then \`family\`; compatible family, league, and time filters are applied together.\
> \- \`scope=leagues\` changes the response shape to \`leagues\_list\` instead of \`parent\_markets\_list\`.\
> \- \`cname=...\` filters by canonical name.\
> \- \`parent\_market\_type\`, \`league\_id\`, and \`family\` filter the parent set.\
> \- \`start\_time\` / \`end\_time\` filter fixture parents by \`fixture.game\_start\_time\`.\
> \- \`omit\_inactive\_with\_redeemed\_on\_before\` excludes parents whose \`redeemed\_on\` is before the given RFC3339 instant, while still returning active parents and more recently redeemed parents.\
> \- \`order=asc|desc\` orders fixture parents by kickoff; fixture discovery defaults to ascending.\
> \- \`omitempty=true\` only affects \`scope=leagues\`.\
> \
> Getting active markets:\
> \- There is no \`active=true\`, \`active\_only=true\`, or \`status=active\` query filter.\
> \- Use \`verbose=true\&limit=50\&offset=0\&omit\_inactive\_with\_redeemed\_on\_before=\<CURRENT\_UTC\_TIMESTAMP>\`;\
> &#x20; replace the placeholder with a URL-encoded current RFC3339 timestamp.\
> \- The cutoff reduces redeemed history; it does not filter individual child statuses.\
> &#x20; Parents redeemed at or after the cutoff may remain, as may non-active children of unredeemed parents.\
> \- Keep parents with \`parent\_market\_data.status == "active"\`, then filter their\
> &#x20; \`markets\[]\` to \`status == "active"\` and discard parents with no active children.\
> \- Keep the cutoff and other filters fixed across pages. Increment \`offset\` by \`limit\`\
> &#x20; until \`data.total\` is exhausted, even when a page yields zero active children.\
> &#x20; \`data.total\` is not an active-child count.\
> \- \`start\_time\` / \`end\_time\` filter fixture kickoff times, not market status;\
> &#x20; \`default=true\` selects the default discovery scope, not every active market.\
> \- Recheck the selected child status before submitting an order.\
> \
> Runtime eligibility convention used by market-maker style clients:\
> \- treat parent \`parent\_market\_data.status == "redeemed"\` as terminal;\
> \- require the target child \`markets\[].status == "active"\`;\
> \- treat child statuses such as \`resolved\` or \`redeemed\` as terminal/not quote eligible;\
> \- validate external/orderbook liquidity before enabling a market for automated quoting.\
> \*\*Public endpoint — no auth required.\*\*<br>

````json
{"openapi":"3.1.0","info":{"title":"PRED Trading Platform API","version":"1.2.0"},"tags":[{"name":"Market Discovery","description":"Market information and discovery (public; no auth). Use this section to understand **parent_market_id** and **market_id** and to list all markets.\n\n## What are parent_market_id and market_id?\n\n- **parent_market_id:** Identifies a parent market (e.g. a fixture or event). It groups one or more child markets. Order and orderbook paths are scoped by parent (e.g. `GET /api/v1/order/{parentMarketID}/orderbook/{marketID}`). Cancel and open-orders endpoints are also per parent.\n- **market_id:** Identifies a specific (child) market within a parent (e.g. one outcome: Team A, Team B, or Draw). Used in place order body (`market_id`), orderbook path (`marketID`), and cancel body. Each parent can have multiple child markets; each child has its own `market_id`.\n\nYou need both when placing orders (parent in the path, market_id in the body) and when fetching orderbooks (parent and market in the path).\n\n## Getting parent_market_id and market_id\n\n**Get all markets:** Call `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0`, then continue paging with `offset += limit` until all `data.total` rows are consumed. `verbose=true` is required for the trading-critical fields that non-verbose responses can omit: `parent_market_data.parent_market_id`, `parent_market_data.type_reference_id`, `parent_market_data.contract_address`, `parent_market_data.parent_market_type`, `parent_market_data.parent_market_family`, and fixture fields such as `fixture.fixture_id` and `fixture.game_start_time`. The response shape is `data.parent_markets_list[]`, where each entry has `parent_market_data`, optional `fixture`, optional `team_data`, and child `markets[]`.\n\n## Discovering active markets\n\nThere is currently **no `active=true`, `active_only=true`, or `status=active` query filter** on\n`GET /api/v1/market-discovery/discover`. To reduce historical results, use:\n\n```http\nGET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0&omit_inactive_with_redeemed_on_before=<CURRENT_UTC_TIMESTAMP>\n```\n\nReplace `<CURRENT_UTC_TIMESTAMP>` with a URL-encoded RFC3339 instant, for example\n`2026-09-09T12:00:00Z` (illustrative only; supply the current time when starting a scan).\nKeep that cutoff and the other filters unchanged while paging with `offset += limit`.\n\nThis is a **parent redemption-time filter, not an active-only filter**. It excludes parents\nwith `redeemed_on` strictly before the cutoff, and parents with `status == \"redeemed\"`\nbut no `redeemed_on`. Parents redeemed exactly at or after the cutoff can still appear.\nAn unredeemed parent can also contain closed or resolved child markets.\n\nFor an active trading list, keep entries whose `parent_market_data.status == \"active\"`,\nthen keep only their children where `markets[].status == \"active\"`; discard entries with\nno remaining children. Continue pagination even if a page has no active children:\n`data.total` describes the server-filtered parent feed, not the number of active children.\nRefresh the selected market's status before placing an order.\n\nDo not use `start_time=<now>` as an active-status substitute: it filters fixture kickoff\ntimes and can exclude otherwise active markets. Likewise, `default=true` selects the\ndefault discovery flow rather than all active markets. Omit both when scanning the full\ndiscover-visible active set, unless you intentionally want their narrower scope.\n\n**Fees:** discovery may include parent-level `parent_market_data.fee_rate_bps`. That value is the market's **target** fee-curve peak (basis points), **not** the value to sign on place-order. Compute the price-distorted signed rate (see **Orders → Fees**). The legacy SDK defaults a missing target to `0`; new integrations should stop and confirm missing configuration with PRED instead of assuming the market is fee-free. Explicit target `0` is valid.\n\n**Runtime eligibility used by market-maker style clients:** first filter your own configured markets to `active`; then require the discovered parent row to have `parent_market_data.status == \"active\"`; then require the specific child row in `markets[]` to have `status == \"active\"`. Child statuses such as `resolved` or `redeemed` are terminal and should be treated as not quote/trade eligible. For market makers, also validate the PRED orderbook or external liquidity source for the child before enabling quoting.\n\n**Important field mapping:** use `parent_market_data.parent_market_id` as the parent path parameter, `markets[].market_id` as the child `market_id`, `parent_market_data.type_reference_id` as the stable Ably orderbook channel key, `parent_market_data.contract_address` as the EIP-712 `verifyingContract`, `parent_market_data.parent_market_family` for family-level config, `parent_market_data.parent_market_type` to distinguish fixtures from generic/futures markets, and `fixture.game_start_time` for fixture/live-window logic.\n\nTo get details for a single parent (including its child market IDs and statuses), call `GET /api/v1/market-discovery/parents/{parentMarketID}`.\n\n## Endpoints\n\n- `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0` — paginated discovery feed for parent markets, child markets, contract addresses, market family/type, and fixture context.\n- `GET /api/v1/market-discovery/parents/{parentMarketID}` — details for one parent, including child markets.\n"}],"servers":[{"url":"https://www.pred.app","description":"PRED API on Base (chain ID 8453)."}],"paths":{"/api/v1/market-discovery/discover":{"get":{"tags":["Market Discovery"],"summary":"Get market discovery feed","description":"Returns discovery entries with parent market data, fixture context, team data, and markets.\nTrading clients should call this endpoint with `verbose=true` and paginate with `limit`/`offset`\nuntil `data.total` is exhausted. Recommended page size for SDK/market-maker style clients is\n`limit=50`; avoid bursts above roughly 10 discovery requests per second.\n\n`verbose=true` is required so `parent_market_data.parent_market_id`,\n`parent_market_data.contract_address`, `parent_market_data.parent_market_type`,\n`parent_market_data.parent_market_family`, and fixture metadata are included reliably.\nNon-verbose responses can omit these fields.\n\nUse `data.parent_markets_list[].parent_market_data.contract_address` as EIP-712\n`verifyingContract` when signing place orders for that parent market.\n\nStatus semantics:\n- parent `parent_market_data.status` typically remains `active` until the parent is fully redeemed; once redeemed it becomes `redeemed`.\n- child `markets[].status` is the eligibility field to check for a specific market and can differ from the parent (for example, a parent may still be `active` while an individual child market is `closed`, `resolved`, or `redeemed`).\n\nQuery/filter behavior:\n- no filter is required; default behavior returns all discover-visible parents as a paginated feed.\n- filter resolution precedence is `default=true`, then `cname`, then `parent_market_type`, then `family`; compatible family, league, and time filters are applied together.\n- `scope=leagues` changes the response shape to `leagues_list` instead of `parent_markets_list`.\n- `cname=...` filters by canonical name.\n- `parent_market_type`, `league_id`, and `family` filter the parent set.\n- `start_time` / `end_time` filter fixture parents by `fixture.game_start_time`.\n- `omit_inactive_with_redeemed_on_before` excludes parents whose `redeemed_on` is before the given RFC3339 instant, while still returning active parents and more recently redeemed parents.\n- `order=asc|desc` orders fixture parents by kickoff; fixture discovery defaults to ascending.\n- `omitempty=true` only affects `scope=leagues`.\n\nGetting active markets:\n- There is no `active=true`, `active_only=true`, or `status=active` query filter.\n- Use `verbose=true&limit=50&offset=0&omit_inactive_with_redeemed_on_before=<CURRENT_UTC_TIMESTAMP>`;\n  replace the placeholder with a URL-encoded current RFC3339 timestamp.\n- The cutoff reduces redeemed history; it does not filter individual child statuses.\n  Parents redeemed at or after the cutoff may remain, as may non-active children of unredeemed parents.\n- Keep parents with `parent_market_data.status == \"active\"`, then filter their\n  `markets[]` to `status == \"active\"` and discard parents with no active children.\n- Keep the cutoff and other filters fixed across pages. Increment `offset` by `limit`\n  until `data.total` is exhausted, even when a page yields zero active children.\n  `data.total` is not an active-child count.\n- `start_time` / `end_time` filter fixture kickoff times, not market status;\n  `default=true` selects the default discovery scope, not every active market.\n- Recheck the selected child status before submitting an order.\n\nRuntime eligibility convention used by market-maker style clients:\n- treat parent `parent_market_data.status == \"redeemed\"` as terminal;\n- require the target child `markets[].status == \"active\"`;\n- treat child statuses such as `resolved` or `redeemed` as terminal/not quote eligible;\n- validate external/orderbook liquidity before enabling a market for automated quoting.\n**Public endpoint — no auth required.**\n","operationId":"getAllParentMarkets","parameters":[{"name":"verbose","in":"query","required":false,"description":"Must be true for trading clients; includes parent_market_id, contract_address, parent_market_type, parent_market_family, fixture metadata, and other verbose parent fields. `default=true` also implies verbose output.","schema":{"type":"boolean","default":false}},{"name":"default","in":"query","required":false,"description":"When true, uses the default discovery flow (primary fixture: recent-started in window, else earliest upcoming, else most recent past). Paginated with the same `limit`/`offset` mechanics as normal discover.","schema":{"type":"boolean","default":false}},{"name":"cname","in":"query","required":false,"description":"Exact type-reference canonical name. Archived parents and markets may be returned; deleted and created records remain excluded.","schema":{"type":"string"}},{"name":"parent_market_type","in":"query","required":false,"description":"Parent market type filter.","schema":{"type":"string","enum":["fixture","generic"]}},{"name":"family","in":"query","required":false,"description":"Parent-market family, for example `moneyline`, `spread`/`spreads`, `total`/`totals`, or `btts`. Aliases are normalized; family paging keeps a fixture/type value's matching parent lines together.","schema":{"type":"string"}},{"name":"league_id","in":"query","required":false,"description":"League UUID filter. Applied only when `parent_market_type` is also supplied.","schema":{"type":"string","format":"uuid"}},{"name":"scope","in":"query","required":false,"description":"`scope=leagues` returns a different response shape (`leagues_list`). Other values currently follow normal parent-market discovery.","schema":{"type":"string"}},{"name":"start_time","in":"query","required":false,"description":"RFC3339 strict lower bound for fixture `game_start_time`. A value representing the current time also includes fixtures started during the preceding three hours.","schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","required":false,"description":"RFC3339 upper bound for fixture `game_start_time` (exclusive).","schema":{"type":"string","format":"date-time"}},{"name":"omit_inactive_with_redeemed_on_before","in":"query","required":false,"description":"Parent redemption-time cutoff in RFC3339 format. Excludes parents whose `redeemed_on`\nis strictly before this instant, plus parents with `status == \"redeemed\"` and no\n`redeemed_on`. Equality is retained: parents redeemed at or after the cutoff may remain.\n\nTo reduce redeemed history while discovering active markets, use the current UTC\ntime at the start of the scan and keep it fixed across pages. This is not an\nactive-only filter and does not filter child `markets[].status`. Clients must\nstill retain active parents and active children explicitly. There is no separate\n`active` / `active_only` / `status` query parameter on this endpoint.\nOmit this parameter to leave this redemption-time exclusion unapplied.\nInvalid timestamps return HTTP 400. URL-encode the value, especially `+` in offsets.\n","schema":{"type":"string","format":"date-time"}},{"name":"order","in":"query","required":false,"description":"Sort order for fixture-backed parents by `fixture.game_start_time`.","schema":{"type":"string","enum":["asc","desc"]}},{"name":"omitempty","in":"query","required":false,"description":"Used with `scope=leagues`; when true, omits leagues with no upcoming fixture and no live/recent match.","schema":{"type":"boolean","default":false}},{"name":"top","in":"query","required":false,"description":"Legacy alias for `limit` when `limit` is unset.","schema":{"type":"integer","maximum":100}},{"name":"limit","in":"query","required":false,"description":"Pagination limit, default 20 and capped at 100. Recommended value for full-feed clients is 50; continue paging until data.total is exhausted. Zero, negative, or invalid values use the default/fallback.","schema":{"type":"integer","default":20,"maximum":100}},{"name":"limt","in":"query","required":false,"deprecated":true,"description":"Legacy typo alias for `limit`, used only when `limit` resolves to zero. Prefer `limit`.","schema":{"type":"integer","maximum":100}},{"name":"offset","in":"query","required":false,"description":"Pagination offset. Start at 0 and increment by limit for each page; negative or invalid values resolve to zero.","schema":{"type":"integer","default":0,"minimum":0}}],"responses":{"200":{"description":"Discovery response. Most query combinations return `parent_markets_list`; `scope=leagues` returns `leagues_list`.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/MarketDiscoveryDiscoverResponse"},{"$ref":"#/components/schemas/MarketDiscoveryDiscoverLeaguesResponse"}]}}}},"400":{"description":"Invalid RFC3339 time or order value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"MarketDiscoveryDiscoverResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"parent_markets_list":{"type":"array","description":"Paginated list of parent-market discovery entries. Full-feed clients should keep requesting pages until `offset + parent_markets_list.length >= total`.","items":{"$ref":"#/components/schemas/MarketDiscoveryDiscoverItem"}},"aggregated_data":{"type":"array","items":{"type":"object","properties":{"canonical_name":{"type":"string"},"super_parent_market_volume":{"type":"string"}}}},"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer","description":"Total number of parent-market entries available across all pages."}}}}},"MarketDiscoveryDiscoverItem":{"type":"object","properties":{"league_data":{"$ref":"#/components/schemas/MarketDiscoveryLeagueData"},"parent_market_data":{"type":"object","description":"Verbose parent market metadata. Trading clients should request `verbose=true` so these fields are populated.","properties":{"parent_market_id":{"type":"string","description":"Parent market ID used in order/orderbook/cancel/open-orders path parameters."},"type_reference_id":{"type":"string","description":"Stable type-reference identifier used as the consolidated Ably market channel key (`market:{typeReferenceId}`)."},"contract_address":{"type":"string","description":"EIP-712 order contract address for this parent market; use as verifyingContract when signing orders."},"parent_market_type":{"type":"string","description":"Parent type, for example `fixture` for sports fixtures; non-fixture/generic markets do not have live-score fixture metadata."},"parent_market_family":{"type":"string","description":"Parent market family such as moneyline, spread, total, or generic; useful for family-level client config."},"canonical_name":{"type":"string","description":"Stable canonical parent market slug/name."},"title":{"type":"string","description":"Human-readable parent market title."},"parent_market_display_name":{"type":"string","description":"Optional display label for the parent market."},"status":{"type":"string","description":"Parent market status. This commonly remains `active` until the parent is fully redeemed, then becomes `redeemed`."},"markets_open":{"type":"string","format":"date-time","description":"Parent market close/open-until timestamp when provided."},"market_line":{"type":"string"},"rules":{"type":"string"},"parent_market_volume":{"type":"string"},"contract_type":{"type":"string"},"fee_rate_bps":{"type":"integer","description":"Parent-level **target** trading fee in basis points (curve peak). Not the value to put on place-order.\nClients must compute the price-distorted signed rate from this target and the order price (see Orders → Fees).\nExplicit `0` is fee-free. Legacy clients default a missing field to `0`; new integrations should confirm missing configuration with PRED before trading.\n"},"logo_url":{"type":"string"},"theme_color":{"type":"string"}}},"fixture":{"type":"object","properties":{"fixture_id":{"type":"string"},"name":{"type":"string"},"alternate_name":{"type":"string"},"game_start_time":{"type":"string","format":"date-time"},"game_status":{"type":"string"},"home_team_id":{"type":"string"},"home_team_score":{"type":"integer"},"away_team_id":{"type":"string"},"away_team_score":{"type":"integer"},"group_by":{"type":"string"},"match_day":{"type":"integer"},"canonical_name":{"type":"string"}}},"team_data":{"type":"array","items":{"type":"object","properties":{"team_id":{"type":"string"},"name":{"type":"string"},"alternate_name":{"type":"string"},"logo_url":{"type":"string"},"theme_color":{"type":"string"}}}},"markets":{"type":"array","description":"Child markets under this parent. Each child has its own market_id and status.","items":{"type":"object","properties":{"market_id":{"type":"string","description":"Child market ID used as `market_id` in order bodies and orderbook paths."},"name":{"type":"string"},"alternate_name":{"type":"string"},"team_id":{"type":"string"},"status":{"type":"string","description":"Child market status. Use this as the trade-eligibility check for a specific market; treat `resolved` and `redeemed` as terminal."},"tick_size":{"type":"string"},"rules":{"type":"string"},"winner":{"type":"string","enum":["long","short"]},"ltp":{"type":"string"},"volume":{"type":"string"},"mid_price":{"type":"string"},"percentage_change":{"type":"string"}}}},"sports_info":{"type":"object","properties":{"game_id":{"type":"string"},"default_source":{"type":"string"},"game_status":{"type":"string"},"home_score":{"type":"integer"},"away_score":{"type":"integer"},"is_genius_mapped":{"type":"boolean"},"genius_fixture_id":{"type":"string"}}}}},"MarketDiscoveryLeagueData":{"type":"object","properties":{"league_id":{"type":"string"},"name":{"type":"string"},"sport":{"type":"string"},"active_logo_url":{"type":"string"},"inactive_logo_url":{"type":"string"},"alternate_name":{"type":"string"},"theme_color":{"type":"string"}}},"MarketDiscoveryDiscoverLeaguesResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"leagues_list":{"type":"array","items":{"$ref":"#/components/schemas/MarketDiscoveryLeagueData"}},"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}}}}},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/Error"},"message":{"type":"string"},"success":{"type":"boolean","default":false}}},"Error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}}}}}
````

## Get parent market details

> Get parent market details including child market IDs and statuses.\
> Use this when you already know a parent market ID and need to confirm its current\
> parent status, child \`markets\[].status\`, market family/type, and contract address.\
> For full-market discovery, prefer the paginated\
> \`GET /api/v1/market-discovery/discover?verbose=true\&limit=50\&offset=0\` flow.\
> \
> Parent \`status\` can remain \`active\` until the parent is fully redeemed, so treat\
> \`status == "redeemed"\` as terminal at the parent level and use child \`markets\[].status\`\
> as the actual market eligibility check. Child statuses such as \`resolved\` or \`redeemed\`\
> are terminal/not quote eligible.\
> \*\*Public endpoint — no auth required.\*\*<br>

````json
{"openapi":"3.1.0","info":{"title":"PRED Trading Platform API","version":"1.2.0"},"tags":[{"name":"Market Discovery","description":"Market information and discovery (public; no auth). Use this section to understand **parent_market_id** and **market_id** and to list all markets.\n\n## What are parent_market_id and market_id?\n\n- **parent_market_id:** Identifies a parent market (e.g. a fixture or event). It groups one or more child markets. Order and orderbook paths are scoped by parent (e.g. `GET /api/v1/order/{parentMarketID}/orderbook/{marketID}`). Cancel and open-orders endpoints are also per parent.\n- **market_id:** Identifies a specific (child) market within a parent (e.g. one outcome: Team A, Team B, or Draw). Used in place order body (`market_id`), orderbook path (`marketID`), and cancel body. Each parent can have multiple child markets; each child has its own `market_id`.\n\nYou need both when placing orders (parent in the path, market_id in the body) and when fetching orderbooks (parent and market in the path).\n\n## Getting parent_market_id and market_id\n\n**Get all markets:** Call `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0`, then continue paging with `offset += limit` until all `data.total` rows are consumed. `verbose=true` is required for the trading-critical fields that non-verbose responses can omit: `parent_market_data.parent_market_id`, `parent_market_data.type_reference_id`, `parent_market_data.contract_address`, `parent_market_data.parent_market_type`, `parent_market_data.parent_market_family`, and fixture fields such as `fixture.fixture_id` and `fixture.game_start_time`. The response shape is `data.parent_markets_list[]`, where each entry has `parent_market_data`, optional `fixture`, optional `team_data`, and child `markets[]`.\n\n## Discovering active markets\n\nThere is currently **no `active=true`, `active_only=true`, or `status=active` query filter** on\n`GET /api/v1/market-discovery/discover`. To reduce historical results, use:\n\n```http\nGET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0&omit_inactive_with_redeemed_on_before=<CURRENT_UTC_TIMESTAMP>\n```\n\nReplace `<CURRENT_UTC_TIMESTAMP>` with a URL-encoded RFC3339 instant, for example\n`2026-09-09T12:00:00Z` (illustrative only; supply the current time when starting a scan).\nKeep that cutoff and the other filters unchanged while paging with `offset += limit`.\n\nThis is a **parent redemption-time filter, not an active-only filter**. It excludes parents\nwith `redeemed_on` strictly before the cutoff, and parents with `status == \"redeemed\"`\nbut no `redeemed_on`. Parents redeemed exactly at or after the cutoff can still appear.\nAn unredeemed parent can also contain closed or resolved child markets.\n\nFor an active trading list, keep entries whose `parent_market_data.status == \"active\"`,\nthen keep only their children where `markets[].status == \"active\"`; discard entries with\nno remaining children. Continue pagination even if a page has no active children:\n`data.total` describes the server-filtered parent feed, not the number of active children.\nRefresh the selected market's status before placing an order.\n\nDo not use `start_time=<now>` as an active-status substitute: it filters fixture kickoff\ntimes and can exclude otherwise active markets. Likewise, `default=true` selects the\ndefault discovery flow rather than all active markets. Omit both when scanning the full\ndiscover-visible active set, unless you intentionally want their narrower scope.\n\n**Fees:** discovery may include parent-level `parent_market_data.fee_rate_bps`. That value is the market's **target** fee-curve peak (basis points), **not** the value to sign on place-order. Compute the price-distorted signed rate (see **Orders → Fees**). The legacy SDK defaults a missing target to `0`; new integrations should stop and confirm missing configuration with PRED instead of assuming the market is fee-free. Explicit target `0` is valid.\n\n**Runtime eligibility used by market-maker style clients:** first filter your own configured markets to `active`; then require the discovered parent row to have `parent_market_data.status == \"active\"`; then require the specific child row in `markets[]` to have `status == \"active\"`. Child statuses such as `resolved` or `redeemed` are terminal and should be treated as not quote/trade eligible. For market makers, also validate the PRED orderbook or external liquidity source for the child before enabling quoting.\n\n**Important field mapping:** use `parent_market_data.parent_market_id` as the parent path parameter, `markets[].market_id` as the child `market_id`, `parent_market_data.type_reference_id` as the stable Ably orderbook channel key, `parent_market_data.contract_address` as the EIP-712 `verifyingContract`, `parent_market_data.parent_market_family` for family-level config, `parent_market_data.parent_market_type` to distinguish fixtures from generic/futures markets, and `fixture.game_start_time` for fixture/live-window logic.\n\nTo get details for a single parent (including its child market IDs and statuses), call `GET /api/v1/market-discovery/parents/{parentMarketID}`.\n\n## Endpoints\n\n- `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0` — paginated discovery feed for parent markets, child markets, contract addresses, market family/type, and fixture context.\n- `GET /api/v1/market-discovery/parents/{parentMarketID}` — details for one parent, including child markets.\n"}],"servers":[{"url":"https://www.pred.app","description":"PRED API on Base (chain ID 8453)."}],"paths":{"/api/v1/market-discovery/parents/{parentMarketID}":{"get":{"tags":["Market Discovery"],"summary":"Get parent market details","description":"Get parent market details including child market IDs and statuses.\nUse this when you already know a parent market ID and need to confirm its current\nparent status, child `markets[].status`, market family/type, and contract address.\nFor full-market discovery, prefer the paginated\n`GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0` flow.\n\nParent `status` can remain `active` until the parent is fully redeemed, so treat\n`status == \"redeemed\"` as terminal at the parent level and use child `markets[].status`\nas the actual market eligibility check. Child statuses such as `resolved` or `redeemed`\nare terminal/not quote eligible.\n**Public endpoint — no auth required.**\n","operationId":"getParentMarketDetails","parameters":[{"$ref":"#/components/parameters/ParentMarketIDPath"}],"responses":{"200":{"description":"Parent market details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParentMarketDetailsResponse"}}}},"404":{"description":"Parent market not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"parameters":{"ParentMarketIDPath":{"name":"parentMarketID","in":"path","required":true,"description":"Parent market ID (bytes32 hex). See **Market Discovery** for what parent_market_id is and how to get it (e.g. from GET /api/v1/market-discovery/discover).","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$"}}},"schemas":{"ParentMarketDetailsResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"parent_market_data":{"type":"object","properties":{"parent_market_id":{"type":"string"},"type_reference_id":{"type":"string","description":"Stable type-reference identifier used as the consolidated Ably market channel key (`market:{typeReferenceId}`)."},"canonical_name":{"type":"string"},"title":{"type":"string"},"parent_market_display_name":{"type":"string"},"markets_open":{"type":"string","format":"date-time"},"status":{"type":"string"},"parent_market_family":{"type":"string"},"market_line":{"type":"string"},"rules":{"type":"string"},"parent_market_volume":{"type":"string"},"contract_type":{"type":"string"},"contract_address":{"type":"string"},"fee_rate_bps":{"type":"integer","description":"Parent-level **target** trading fee in basis points (curve peak). Not the value to put on place-order.\nClients must compute the price-distorted signed rate from this target and the order price (see Orders → Fees).\nExplicit `0` is fee-free. Legacy clients default a missing field to `0`; new integrations should confirm missing configuration with PRED before trading.\n"},"logo_url":{"type":"string"},"theme_color":{"type":"string"},"parent_market_type":{"type":"string"}}},"markets":{"type":"array","items":{"type":"object","properties":{"market_id":{"type":"string"},"team_id":{"type":"string"},"name":{"type":"string"},"logo_url":{"type":"string"},"alternate_name":{"type":"string"},"status":{"type":"string"},"tick_size":{"type":"string"},"rules":{"type":"string"},"winner":{"type":"string","enum":["long","short"]},"ltp":{"type":"string"},"volume":{"type":"string"},"mid_price":{"type":"string"},"percentage_change":{"type":"string"}}}}}}}},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/Error"},"message":{"type":"string"},"success":{"type":"boolean","default":false}}},"Error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}}}}}
````

## Get parent details by child market ID

> Get the parent market and sibling \`markets\[]\` for a child \`market\_id\`.\
> This returns the same discover-style \`parent\_market\_data + markets\[]\` payload shape as the parent-by-id endpoint, but is addressed by child market ID instead of parent market ID.\
> \
> This is useful when you only have a child \`market\_id\` and need its parent contract address, parent status, sibling markets, or parent-level \`fee\_rate\_bps\`.\
> \*\*Public endpoint — no auth required.\*\*<br>

````json
{"openapi":"3.1.0","info":{"title":"PRED Trading Platform API","version":"1.2.0"},"tags":[{"name":"Market Discovery","description":"Market information and discovery (public; no auth). Use this section to understand **parent_market_id** and **market_id** and to list all markets.\n\n## What are parent_market_id and market_id?\n\n- **parent_market_id:** Identifies a parent market (e.g. a fixture or event). It groups one or more child markets. Order and orderbook paths are scoped by parent (e.g. `GET /api/v1/order/{parentMarketID}/orderbook/{marketID}`). Cancel and open-orders endpoints are also per parent.\n- **market_id:** Identifies a specific (child) market within a parent (e.g. one outcome: Team A, Team B, or Draw). Used in place order body (`market_id`), orderbook path (`marketID`), and cancel body. Each parent can have multiple child markets; each child has its own `market_id`.\n\nYou need both when placing orders (parent in the path, market_id in the body) and when fetching orderbooks (parent and market in the path).\n\n## Getting parent_market_id and market_id\n\n**Get all markets:** Call `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0`, then continue paging with `offset += limit` until all `data.total` rows are consumed. `verbose=true` is required for the trading-critical fields that non-verbose responses can omit: `parent_market_data.parent_market_id`, `parent_market_data.type_reference_id`, `parent_market_data.contract_address`, `parent_market_data.parent_market_type`, `parent_market_data.parent_market_family`, and fixture fields such as `fixture.fixture_id` and `fixture.game_start_time`. The response shape is `data.parent_markets_list[]`, where each entry has `parent_market_data`, optional `fixture`, optional `team_data`, and child `markets[]`.\n\n## Discovering active markets\n\nThere is currently **no `active=true`, `active_only=true`, or `status=active` query filter** on\n`GET /api/v1/market-discovery/discover`. To reduce historical results, use:\n\n```http\nGET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0&omit_inactive_with_redeemed_on_before=<CURRENT_UTC_TIMESTAMP>\n```\n\nReplace `<CURRENT_UTC_TIMESTAMP>` with a URL-encoded RFC3339 instant, for example\n`2026-09-09T12:00:00Z` (illustrative only; supply the current time when starting a scan).\nKeep that cutoff and the other filters unchanged while paging with `offset += limit`.\n\nThis is a **parent redemption-time filter, not an active-only filter**. It excludes parents\nwith `redeemed_on` strictly before the cutoff, and parents with `status == \"redeemed\"`\nbut no `redeemed_on`. Parents redeemed exactly at or after the cutoff can still appear.\nAn unredeemed parent can also contain closed or resolved child markets.\n\nFor an active trading list, keep entries whose `parent_market_data.status == \"active\"`,\nthen keep only their children where `markets[].status == \"active\"`; discard entries with\nno remaining children. Continue pagination even if a page has no active children:\n`data.total` describes the server-filtered parent feed, not the number of active children.\nRefresh the selected market's status before placing an order.\n\nDo not use `start_time=<now>` as an active-status substitute: it filters fixture kickoff\ntimes and can exclude otherwise active markets. Likewise, `default=true` selects the\ndefault discovery flow rather than all active markets. Omit both when scanning the full\ndiscover-visible active set, unless you intentionally want their narrower scope.\n\n**Fees:** discovery may include parent-level `parent_market_data.fee_rate_bps`. That value is the market's **target** fee-curve peak (basis points), **not** the value to sign on place-order. Compute the price-distorted signed rate (see **Orders → Fees**). The legacy SDK defaults a missing target to `0`; new integrations should stop and confirm missing configuration with PRED instead of assuming the market is fee-free. Explicit target `0` is valid.\n\n**Runtime eligibility used by market-maker style clients:** first filter your own configured markets to `active`; then require the discovered parent row to have `parent_market_data.status == \"active\"`; then require the specific child row in `markets[]` to have `status == \"active\"`. Child statuses such as `resolved` or `redeemed` are terminal and should be treated as not quote/trade eligible. For market makers, also validate the PRED orderbook or external liquidity source for the child before enabling quoting.\n\n**Important field mapping:** use `parent_market_data.parent_market_id` as the parent path parameter, `markets[].market_id` as the child `market_id`, `parent_market_data.type_reference_id` as the stable Ably orderbook channel key, `parent_market_data.contract_address` as the EIP-712 `verifyingContract`, `parent_market_data.parent_market_family` for family-level config, `parent_market_data.parent_market_type` to distinguish fixtures from generic/futures markets, and `fixture.game_start_time` for fixture/live-window logic.\n\nTo get details for a single parent (including its child market IDs and statuses), call `GET /api/v1/market-discovery/parents/{parentMarketID}`.\n\n## Endpoints\n\n- `GET /api/v1/market-discovery/discover?verbose=true&limit=50&offset=0` — paginated discovery feed for parent markets, child markets, contract addresses, market family/type, and fixture context.\n- `GET /api/v1/market-discovery/parents/{parentMarketID}` — details for one parent, including child markets.\n"}],"servers":[{"url":"https://www.pred.app","description":"PRED API on Base (chain ID 8453)."}],"paths":{"/api/v1/market-discovery/parents":{"get":{"tags":["Market Discovery"],"summary":"Get parent details by child market ID","description":"Get the parent market and sibling `markets[]` for a child `market_id`.\nThis returns the same discover-style `parent_market_data + markets[]` payload shape as the parent-by-id endpoint, but is addressed by child market ID instead of parent market ID.\n\nThis is useful when you only have a child `market_id` and need its parent contract address, parent status, sibling markets, or parent-level `fee_rate_bps`.\n**Public endpoint — no auth required.**\n","operationId":"getParentMarketByMarketID","parameters":[{"name":"market_id","in":"query","required":true,"description":"Child market ID.","schema":{"type":"string"}}],"responses":{"200":{"description":"Parent market details for the given child market ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParentMarketDetailsResponse"}}}},"404":{"description":"Parent market not found for the given child market ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"ParentMarketDetailsResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"parent_market_data":{"type":"object","properties":{"parent_market_id":{"type":"string"},"type_reference_id":{"type":"string","description":"Stable type-reference identifier used as the consolidated Ably market channel key (`market:{typeReferenceId}`)."},"canonical_name":{"type":"string"},"title":{"type":"string"},"parent_market_display_name":{"type":"string"},"markets_open":{"type":"string","format":"date-time"},"status":{"type":"string"},"parent_market_family":{"type":"string"},"market_line":{"type":"string"},"rules":{"type":"string"},"parent_market_volume":{"type":"string"},"contract_type":{"type":"string"},"contract_address":{"type":"string"},"fee_rate_bps":{"type":"integer","description":"Parent-level **target** trading fee in basis points (curve peak). Not the value to put on place-order.\nClients must compute the price-distorted signed rate from this target and the order price (see Orders → Fees).\nExplicit `0` is fee-free. Legacy clients default a missing field to `0`; new integrations should confirm missing configuration with PRED before trading.\n"},"logo_url":{"type":"string"},"theme_color":{"type":"string"},"parent_market_type":{"type":"string"}}},"markets":{"type":"array","items":{"type":"object","properties":{"market_id":{"type":"string"},"team_id":{"type":"string"},"name":{"type":"string"},"logo_url":{"type":"string"},"alternate_name":{"type":"string"},"status":{"type":"string"},"tick_size":{"type":"string"},"rules":{"type":"string"},"winner":{"type":"string","enum":["long","short"]},"ltp":{"type":"string"},"volume":{"type":"string"},"mid_price":{"type":"string"},"percentage_change":{"type":"string"}}}}}}}},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/Error"},"message":{"type":"string"},"success":{"type":"boolean","default":false}}},"Error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}}}}}
````
