You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: changelog.md
+20Lines changed: 20 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,26 @@
2
2
3
3
All notable changes to this project will be documented in this file.
4
4
5
+
## [2.50.10] - 2026-06-18
6
+
7
+
### Fixed
8
+
9
+
A code-correctness audit against the SDK source found 8 HIGH-severity bugs in published docs — code blocks that would TypeError, AttributeError, or silently no-op. Two of them I introduced myself in 2.50.6 by rewriting against the wrong SDK truth. All fixed in parallel with three agents, each verifying against the SDK source line they cite.
10
+
11
+
-**`docs/authentication.mdx:107` + `docs/guides/self-hosted.mdx:93`**: Python `create_order(type="limit", ...)` would raise `TypeError: unexpected keyword argument 'type'`. The parameter is `order_type=`, not `type=` (`sdks/python/pmxt/client.py:2892`). Fixed both call sites.
12
+
-**`docs/guides/escrow-lifecycle.mdx:118,124`**: Self-introduced regression from 2.50.6. After fixing `fetch_balance` to return a list, I documented `usdc.free / .used / .total` — those fields don't exist. The Balance dataclass exposes `available` / `locked` / `total` (`sdks/python/pmxt/models.py:596-603`; `sdks/typescript/pmxt/models.ts:387-393`). `.free` and `.used` would AttributeError on first access. Updated both Python and TypeScript examples to use the real field names.
13
+
-**`docs/router/prices.mdx:206`**: `poly.fetch_order_book(market_id=clusters[0].markets[0].market_id)` — `fetch_order_book` takes `outcome_id`, not `market_id` (`sdks/python/pmxt/client.py:1441`). The `_compat_id` resolver at line 1446 would catch the missing required arg and raise `TypeError: Missing required argument: 'outcome_id'`. Updated to pull an outcome ID from `clusters[0].markets[0].outcomes[0].outcome_id`.
14
+
-**`docs/concepts/catalog-uuid-vs-venue-id.mdx:48-56`**: The "reverse-resolve a venue ID to a catalog UUID" example showed `router.fetch_matched_market_clusters(venue="polymarket", venue_market_id="0x...")` then read `clusters[0].market_id`. None of those exist: the method signature (`sdks/python/pmxt/router.py:328-350`) accepts only `market_id`, `slug`, `url`, `query`, `venues`/`exclude_venues`, and `MatchedMarketCluster` (`models.py:939-964`) has `cluster_id` + `markets[]` with no top-level `market_id`. There is no clean SDK reverse-resolution API for the venue→catalog mapping. Replaced the broken example with a `POST /v0/sql` query against `prediction_markets.markets` filtered by `venue` + `venue_market_id` — which is what the next paragraph of the page already pointed at.
15
+
-**`docs/guides/signing.mdx` — `## Advanced: bring your own signer`**: The 2.50.6 rewrite of this section shipped a Python pattern that doesn't work and a TypeScript pattern that throws on the first call. Two distinct bugs:
16
+
-**Python:** the pattern was `built = client.build_order(...); built.signed_order = my_signer.sign_typed_data(...); client.submit_order(built)`. In hosted mode, `submit_order` ignores `built.signed_order` and re-signs internally with `self.signer` (`client.py:875-895` in `_call_hosted_signer`; `client.py:911` reads `signer or self.signer`; `client.py:3203``_hosted_submit_body(..., signer=None)` falls back). The custom signature was silently discarded and the user's `private_key` was used instead. Anyone following the doc would think their custom signer worked when in fact only the `private_key` path was active.
17
+
-**TypeScript:** worse — `submitOrder` is explicitly disabled in hosted mode and throws `PmxtError("submitOrder is not available in hosted mode. Use createOrder instead.")` (`client.ts:1134-1137`). The TS recipe could never run.
-**Signer protocol:** the Python signer must implement `sign_typed_data(typed_data: dict) -> hex` — taking the WHOLE typed-data dict (`client.py:875-895` iterates `("sign_typed_data", "sign")` and passes the full dict). The 2.50.6 docs incorrectly showed a split `domain=/types=/message=` signature; that was wrong. The TS Signer protocol (`signers.ts:33-35`) is `{ address: string; signTypedData(typedData: TypedData): Promise<string> }`. Rewrote both examples to constructor-inject and call `create_order` / `createOrder`. Removed the build/sign/submit dance entirely — it's not a hosted-mode pattern.
20
+
-**`docs/guides/signing.mdx` — TS field names**: TS `buildOrder`/`createOrder` examples used `orderType:` and `slippagePct:`. The `CreateOrderParams` interface (`models.ts:533-545`) uses `type:` (not `orderType`). Slippage is even more unusual — TS forwards it through the params extension dict as the snake_case key `slippage_pct:` (`client.ts:2429-2430`). The TS field name really is snake_case here; that's not a typo. Updated all TS examples.
-**`docs/guides/hosted-errors.mdx` — `BuiltOrderExpired` retry pattern (`lines 150-187`)**: same build/sign/submit pattern problem as `signing.mdx`. The retry example showed `built.signed_order = ...; submit_order(built)`. Same issue: Python hosted ignores the assignment and re-signs; TS hosted throws. Rewrote both examples to call `create_order` / `createOrder` directly inside the try/except — the SDK's convenience wrapper handles build → sign → submit atomically, so a `BuiltOrderExpired` retry is just calling `create_order` again.
23
+
-**`docs/api-reference/fetch-ohlcv.mdx:7`**: Broken internal link `/dashboard` (an in-docs path that doesn't exist) replaced with the external `https://pmxt.dev/dashboard`. The only broken internal link in the docs tree per the link-integrity sweep.
Copy file name to clipboardExpand all lines: docs/api-reference/fetch-ohlcv.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ openapi: GET /api/{exchange}/fetchOHLCV
4
4
---
5
5
6
6
<Info>
7
-
**More data with an API key** — Without an API key, OHLCV is limited to Polymarket's native API: short history windows, no volume, and venue-specific rate limits. With a PMXT API key you get volume, 1+ years of history, and normalized candles across venues. Kalshi, Limitless, and more are coming soon. [Get your API key](/dashboard).
7
+
**More data with an API key** — Without an API key, OHLCV is limited to Polymarket's native API: short history windows, no volume, and venue-specific rate limits. With a PMXT API key you get volume, 1+ years of history, and normalized candles across venues. Kalshi, Limitless, and more are coming soon. [Get your API key](https://pmxt.dev/dashboard).
The SDK does not expose a single-shot `venue_market_id` -> catalog UUID kwarg today. For batch or one-off reverse lookups, query the catalog directly via `POST /v0/sql`:
49
+
50
+
```sql
51
+
SELECT market_id
52
+
FROMprediction_markets.markets
53
+
WHERE venue ='polymarket'
54
+
AND venue_market_id ='0xc704f74e2f9dfae70f770cb253ffadde10768eeab41233098bf5ac67995a94b5';
54
55
```
55
56
56
-
For batch workflows, `POST /v0/sql` gives you direct access to `prediction_markets.markets` and `prediction_markets.outcomes`with the canonical UUID alongside the venue-native fields (`venue_market_id`, `venue_outcome_id` / `token_id`).
57
+
`prediction_markets.markets` and `prediction_markets.outcomes`carry the canonical UUID alongside the venue-native fields (`venue_market_id`, `venue_outcome_id` / `token_id`), so the same query shape covers outcomes too.
@@ -72,17 +72,19 @@ Because reads don't require a signature, anyone with the `pmxt_api_key` can read
72
72
73
73
## Advanced: bring your own signer
74
74
75
-
If your key lives in a hardware wallet, HSM, MPC service, or anything that isn't a raw hex private key, skip `private_key` and use the lower-level `build_order` / `submit_order` flow. Any object that implements `sign_typed_data(domain, types, message) -> hex` works.
75
+
If your key lives in a hardware wallet, HSM, MPC service, or anything that isn't a raw hex private key, skip `private_key` and inject a custom signer at construction. The SDK uses it transparently for every hosted write — you keep calling `create_order` as usual.
76
+
77
+
The signer protocol is one method: `sign_typed_data(typed_data: dict) -> hex` (Python) or `signTypedData(typedData): Promise<string>` plus a readonly `address` (TypeScript).
For Opinion, `built` carries two payloads (`typed_data` and `pull_typed_data`); sign both and pass `signature` + `pull_signature` to `submit_order`. The SDK's `EthAccountSigner` / `EthersSigner` are reference implementations of the signer protocol — ethers v6 supports Ledger out of the box; for MPC see Fireblocks / Privy / Turnkey docs.
117
+
For Opinion's dual-signature flow, the same injected signer is invoked twice (once per payload) — no extra wiring. The SDK's `EthAccountSigner`(Python) / `EthersSigner`(TypeScript) are reference implementations; ethers v6 supports Ledger out of the box, and for MPC see Fireblocks / Privy / Turnkey docs.
0 commit comments