Releases: pmxt-dev/pmxt
v2.49.7
API Reference sidebar reorder: Trading and Orders & Positions move from near the bottom of the tab to immediately under Events & Markets, so the customer's natural path is walkable top-to-bottom — discover (Events & Markets) → act (Trading) → inspect state (Orders & Positions) → niche features.
Changed
scripts/generate-mintlify-docs.js: The API-tab assembly now inserts bothcrossExchangeGroupsand the hostedotherExternalGroupsafter"Events & Markets". BecauseinsertGroupsAfterpushes the existing target's neighbor down, the second insertion (otherExternalGroups) lands between"Events & Markets"and"Cross Exchange", producing the order:Overview → System → Events & Markets → Trading → Orders & Positions → Cross Exchange → Order Book & Trades → Realtime → Data Feeds → Other → Enterprise. Idempotent — re-running the regenerator produces no diff.
Installation
npm:
npm install pmxtjs@2.49.7
npm install -g @pmxt/cli@2.49.7PyPI:
pip install pmxt==2.49.7Links
Full Changelog: v2.49.6f...v2.49.7f
v2.49.6
Generator-side hotfix for a regression introduced by the v2.49.5 auto-publish: the generate:mintlify step (scripts/generate-mintlify-docs.js, run by .github/workflows/publish.yml on every release tag) was re-injecting self-hosted Group A endpoints as a duplicate "Trading" group (with "Local Only" badges) into docs.json's API Reference tab, sitting alongside the canonical hosted "Trading" group that this release line had just renamed and cleaned up. Result: every release pushed two same-named groups into the rendered sidebar.
Fixed
scripts/generate-mintlify-docs.js: Removed the hardcoded"Trading"and"Orders & Positions"entries from theENDPOINT_GROUPSmatcher array — the generator no longer manufactures those groups from the self-hostedopenapi.json. Added the matching self-hosted operation ids (createOrder,buildOrder,submitOrder,cancelOrder,editOrder,fetchOrder,fetchOpenOrders,fetchClosedOrders,fetchAllOrders,fetchMyTrades,fetchPositions,fetchBalance,fetchOrderHistory) to theHIDDEN_OPERATIONSset so they don't fall through to the"Other"bucket either. Net effect: the next auto-publish keeps the manually-curated hosted"Trading"+"Orders & Positions"groups (rendered fromopenapi-hosted-trading.json) and never re-adds the self-hosted equivalents. Self-hosters who want the full reference still consumeopenapi.jsondirectly or reach it via/guides/self-hosted.docs/docs.json: Removed two stale duplicate groups ("Trading (Hosted)","Orders & Positions (Hosted)") that the 2.49.5 auto-publish had left behind after the rename. The generator is now idempotent — regenerating produces a stable group list.
Installation
npm:
npm install pmxtjs@2.49.6
npm install -g @pmxt/cli@2.49.6PyPI:
pip install pmxt==2.49.6Links
Full Changelog: v2.49.5f...v2.49.6f
v2.49.5
Sidebar cleanup: drop "(Hosted)" suffixes everywhere and hide the parallel self-hosted Group A reference. The hosted endpoints are now the only Group A surface in the sidebar; the API reference reads as "Trading → Create Order" instead of "Trading (Hosted) → Create Order (Hosted)."
Changed
- Sidebar group labels (
docs.json):"Trading (Hosted)"→"Trading","Orders & Positions (Hosted)"→"Orders & Positions"inside the API Reference tab. The "(Hosted)" disambiguation made sense when a sibling self-hosted group existed in the same sidebar; with that group removed (see below), the suffix is just noise. - Operation summaries (
openapi-hosted-trading.json): All 9 hosted opsummaryfields drop the(Hosted)suffix —"Create Order (Hosted)"→"Create Order", etc."Cancel Order -- Build (Hosted)"collapses to"Cancel Order"(the build / sign / submit two-step is already explained in the operation description; the user-facing name shouldn't telegraph internal mechanics). - Operation tags (
openapi-hosted-trading.json):"Trading (Hosted)"→"Trading","Orders & Positions (Hosted)"→"Orders & Positions"on every op. Mintlify derives URL slugs from the tag, so the rendered hosted endpoint URLs go from/api-reference/trading-hosted/create-orderto/api-reference/trading/create-order(and equivalent for Orders & Positions). No external links pointed at the previous slugs.
Removed
"Self-host API reference"sidebar group (docs.json): The 11-page nested group rendering the self-hosted Group A endpoints fromopenapi.json(each operation flagged with a"Local Only"badge) is dropped from the Documentation tab sidebar. It duplicated the hosted endpoints' purpose for most readers and made the sidebar feel cluttered (a "Trading" group with "Local Only"–badged entries sitting alongside the prominent hosted "Trading" group on the API Reference tab). The underlyingopenapi.jsonfile is unchanged — self-hosters who want the full reference can still consume the spec directly or reach the per-method pages via the existing/guides/self-hostednarrative. Net effect on the rendered sidebar: one canonical "Trading" group in the API Reference tab, no parallel "Local Only" entries elsewhere.
Installation
npm:
npm install pmxtjs@2.49.5
npm install -g @pmxt/cli@2.49.5PyPI:
pip install pmxt==2.49.5Links
Full Changelog: v2.49.4f...v2.49.5f
v2.49.4
Hosted-trading docs QA pass. This patch also ships the 2.49.2 doc restructure work that had accumulated dirty in the working tree but never landed (Pattern E sidebar split, custody page, prediction-markets-101 glossary, terminology cleanup, etc. — see the 2.49.2 entry below for the full list).
Changed
- Hosted op descriptions (
openapi-hosted-trading.json): All 9 hosted Group A operations (createOrderHosted,buildOrderHosted,submitOrderHosted,cancelOrderHosted,fetchBalanceHosted,fetchPositionsHosted,fetchOpenOrdersHosted,fetchMyTradesHosted,fetchOrderHosted) rewritten in a user-friendly style: lead with what the customer gets, demote internals (EIP-712, build/sign/submit decomposition, custodial-flow alternatives) to a final paragraph or remove entirely.createOrderHostednow opens with an inline code sample showing the naturalclient.fetch_markets() → client.create_order(outcome=market.yes)chain. No more "EIP-712 typed-data payload" or "PreFundedEscrow balance" in opening sentences. - Non-custodial language sweep across customer-facing concept docs:
docs/concepts/hosted-trading.mdx,docs/concepts/hosted-custody.mdx(new),docs/concepts/hosted-vs-self-hosted.mdx,docs/concepts/prediction-markets-101.mdx(new),docs/trading-quickstart.mdx,docs/guides/escrow-lifecycle.mdxall reworded so the escrow story reads "USDC sits in a non-custodialPreFundedEscrowsmart contract; PMXT cannot move funds without your EIP-712 signature" rather than "PMXT custodies USDC."docs/security.mdxleft alone — its credential-handling discussion is intentional and scoped correctly. - UI-first deposit / withdraw flow on
docs/trading-quickstart.mdxanddocs/guides/escrow-lifecycle.mdx: Both pages now lead the deposit and withdraw sections with a "Recommended: use the dashboard" subsection (connect wallet at pmxt.dev/dashboard/wallet → click Deposit/Withdraw → confirm in your wallet). The previousclient.escrow.approve_tx(...)/deposit_tx(...)/withdraw_tx(...)<CodeGroup>blocks are preserved verbatim but tucked inside<Accordion title="Advanced: programmatic ...">so they're one click away for the scripting / treasury-automation case. x-mint.contentcallouts on all 9 hosted ops (openapi-hosted-trading.json): The funding-prereq<Note>now links directly to pmxt.dev/dashboard/wallet for the one-time deposit (with/guides/escrow-lifecycleas the programmatic-flow fallback), replacing the previous link to the lifecycle guide alone. The EVM-key<Tip>now reads "Your USDC sits in a non-custodialPreFundedEscrowon Polygon — the single funding location for every hosted venue (including Opinion, which PMXT settles cross-chain for you). PMXT cannot move funds without your EIP-712 signature." Previous wording said "PMXT custodies USDC on Polygon for every hosted venue."
Removed
BuildOrderHostedRequest.outcome_id(openapi-hosted-trading.json): Following the same logic asmarket_id(relaxed in 2.49.3),outcome_idis no longer documented as a request property. The schema now only documentsvenue+venue_outcome_idas the way to identify the target outcome. The hosted trading backend continues to acceptoutcome_id(UUID) for backward compatibility — existing callers that send it keep working — but the spec stops promising it as a supported input. Net effect: a new reader looking at the create-order page sees one clean way to identify the outcome instead of an "EITHER (a) catalog UUID OR (b) venue + venue_outcome_id" fork. Schema description tightened to a single sentence.- Dual-identifier framing across the hosted spec: All "catalog UUID" / "Provide this OR" / "venue-native id from fetch_markets()" / "catalog UUID lookup required" language scrubbed from operation descriptions, schema property descriptions, and
x-codeSamplesheader comments. Netgrep -E "catalog UUID|Provide this OR" docs/api-reference/openapi-hosted-trading.jsoncount went from 14 → 0. Response-sideoutcome_id/market_idonOrderV0,UserTradeV0,PositionV0now described as plain "Identifier of the outcome / market this row refers to" without the "catalog UUID" / "cross-venue canonical" framing — readers no longer have to learn an ID-architecture taxonomy before reading a position.
Added
- Per-field descriptions across every hosted-trading spec schema (
openapi-hosted-trading.json): ~129descriptionstrings added to bare properties across 16 schemas (BalanceV0,BuildOrderHostedRequest,BuildOrderHostedResponseand nestedquote/resolved,CancelBuildHostedRequest,CancelBuildHostedResponse,ErrorResponse,HostedErrorResponse,ListMeta,OrderV0,PositionV0,RateLimitError,SubmitOrderHostedRequest,UnifiedEvent,UnifiedMarket,UnifiedOutcome,UserTradeV0). Mintlify now renders meaningful per-field doc strings instead of baretype | nullrows. Descriptions are grounded in the trading backend'smodels_v0.pyPydantic field semantics — e.g.feeis now documented as a USDC dollar amount net of per-fill venue fees,PositionV0.sharesis documented as the ERC-1155 balance held byPreFundedEscrowon behalf of the wallet (not the wallet's on-chain balance), andPositionV0.entry_priceis documented as the v1 cost-basis approximation (sum(buy_quote_micros) / sum(buy_shares_micros), ignoring sells) — with the explicit caveat thatcurrent_price,current_value, andunrealized_pnlare reserved and currently returnnullin this release. Verify-grep on bare properties (jq '... .description == null ...') returns zero records.
Not changed (deliberate)
docs/security.mdx: The mode-scoped credential-handling table is intentional — its "credentials hit process memory ephemerally" claim is scoped to self-hosted mode and correctly distinguishes from the hosted flow (where the private key never leaves the user's machine). Left alone in the non-custodial sweep.- Auto-generated
docs/api-reference/openapi.json(self-hosted spec, regenerated bycore/scripts/generate-openapi.js): the same description / friendly-rewrite passes were not applied because they'd be lost on the next regeneration. If self-hosted reference docs need the same polish later, the source is theSCHEMASliteral insidecore/scripts/generate-openapi.js, not the rendered JSON. - Backend
BuildOrderV0ReqPydantic model (pmxt-trading):outcome_idremains an accepted field at the API layer for backward compatibility with pre-2.49.3 callers. The spec-side removal is documentation-only — no breaking change on the wire.
Installation
npm:
npm install pmxtjs@2.49.4
npm install -g @pmxt/cli@2.49.4PyPI:
pip install pmxt==2.49.4Links
Full Changelog: v2.49.3f...v2.49.4f
v2.49.3
Backend-deploy patch for the venue-native outcome ID acceptance feature described in 2.49.2. Includes a follow-up SDK bug fix discovered during end-to-end verification on Polygon mainnet, plus the doc and test deltas that bring this release to a confirmed working state.
Fixed
- SDK (
sdks/python/pmxt/client.py,sdks/typescript/pmxt/client.ts): When the caller supplies a venue-native outcome identifier (non-UUID string returned byclient.fetch_markets()on a venue client),_hosted_build_order_request/_hostedBuildOrderBodynow correctly suppressmarket_idfrom the wire body instead of forwarding the (also venue-native) value alongsidevenue+venue_outcome_id. Previous behavior caused the backend to reject the request with a UUID-validation error onmarket_id(Input should be a valid UUID, invalid length: expected length 32 for simple format, found 6). The catalog-UUID path is unchanged —market_idis still forwarded when both the suppliedoutcome_idand the suppliedmarket_idare UUID-shaped.
Changed
- Docs (
docs/trading-quickstart.mdx): Step 5 collapsed to the natural single-client chain —client.fetch_markets({"query": "trump 2028"})[0]→client.create_order(outcome=market.yes, side="buy", amount=1.0, denom="usdc", order_type="market", slippage_pct=99.9). The previous Router round-trip +<Warning>againstpmxt.Polymarket().fetch_markets()results is replaced by a<Note>clarifying that both UUID and venue-native ID forms are accepted by the trading API. Step 7 ("Verify the fill") renumbered to Step 6. - Docs (
docs/concepts/catalog-uuid-vs-venue-id.mdx): Rewritten (70 lines down from 91). The page no longer frames the two ID spaces as a footgun. New framing: hosted trading accepts either identifier; the catalog UUID matters specifically for cross-venue identity (matched clusters, portfolio analytics that span venues, stability across venue re-listings) and for self-hosted mode where the catalog isn't in the path. The<Warning>againstpmxt.Polymarket().fetch_markets()results is removed.
Added
- SDK tests: Python
tests/test_hosted_dispatch.pyand TypeScripttests/hosted-dispatch.test.tsgainedtest_build_order_with_venue_native_id_sends_venue_pair/buildOrder with venue-native outcomeId sends (venue, venue_outcome_id)cases asserting the new wire shape (venue,venue_outcome_idpresent;outcome_id,market_idabsent). Existing test constants upgraded from"market-uuid-1"/"outcome-uuid-1"(which the new UUID detection regex would mis-classify as venue-native) to canonical 8-4-4-4-12 UUID strings so the backcompat-UUID test cases continue to assert the right behavior. Net: Python 26/26, TypeScript 18/18.
Verified
- End-to-end on Polygon mainnet: Confirmed the full natural workflow
client.fetch_markets()[0]→client.create_order(outcome=market.yes)→ on-chain settlement →fetch_positions→client.create_order(side="sell")→ on-chain settlement → position closed. Round-trip executed against PreFundedEscrow (0x3ad326f78b1390b9a5dc5f00e7f62f8632de23e2) on the Spain WC 2026 YES outcome: buy 1.000000 USDC → 6.25 shares (tx0x16bcfa7e00c49325bd779b044f71a660899e9d0218b11656e2ca9646a208ba10, block 88201299), sell 6.25 shares → 0.988781 USDC. Net round-trip −0.011 USDC (≈ 1.1%, expected CLOB spread).
Deploy prerequisite met
pmxt-trading(BuildOrderV0Reqaccepts(venue, venue_outcome_id)): deployed inpmxt-dev/pmxt-trading@9983e35.
Installation
npm:
npm install pmxtjs@2.49.3
npm install -g @pmxt/cli@2.49.3PyPI:
pip install pmxt==2.49.3Links
What's Changed
- feat(docs): per-method hosted/self-hosted toggle on Group A reference pages (v2.49.2) by @realfishsam in #979
- docs: rename 'sidecar' to 'local PMXT service' per 2026-05-27 ADR (v2.49.2) by @realfishsam in #980
Full Changelog: v2.49.1f...v2.49.3f
v2.49.1
Positioning-shift patch on top of 2.49.0 — the hosted trading mode shipped in 2.49.0 but the docs, READMEs, and OpenAPI schemas still defaulted to the self-hosted sidecar path. This release flips the default everywhere the SDK + docs surface a customer hits: hosted PMXT is the primary experience; self-hosting becomes the advanced escape hatch. No SDK runtime behavior changes — pure documentation, schema, and copy work. Marketing-site changes ship separately in a sibling pmxt-website PR.
Added
- Docs: 11 new MDX pages on the Mintlify site covering the hosted trading mode end-to-end —
trading-quickstart(60-second walkthrough),concepts/hosted-trading(feature landing),concepts/hosted-vs-self-hosted(one-pager comparison),concepts/catalog-uuid-vs-venue-id(the UUID/venue-id gotcha),guides/escrow-lifecycle(PreFundedEscrow walkthrough),guides/signing(EthAccountSigner / EthersSigner + EIP-712),guides/hosted-errors(the 5 most-common subclasses withtry/exceptcookbook),guides/migrate-to-hosted-trading(portedMIGRATION.mdcontent with language tabs),guides/self-hosted(consolidated local-sidecar story),api-reference/errors(fullHostedTradingErrortree with dual-parent semantic-map),api-reference/configuration(ExchangeOptions+ env vars + base-URL resolution). - Docs: New "Hosted Trading" and "Self-host" sidebar groups in
docs.json, plus a "Reference" group at the top of the API Reference tab.sdk/servermoved out of the previous "SDK" group into "Self-host" (without slug rename — link-stability preserved for this release). - Core: New
ExchangeOptionscomponent schema incore/src/server/openapi.yamldocumenting constructor-level options (pmxtApiKey,walletAddress,signer,privateKey,baseUrl, etc.) — previously onlyExchangeCredentials(per-request body credentials) existed at the schema level. - Core:
BuiltOrder.expiryfield added to the OpenAPI schema (the TTL that triggersBuiltOrderExpiredat submit time was implicit in the SDK and undocumented at the spec level).
Changed
- Docs:
introduction.mdx"It runs two ways" bullet order inverted — hosted listed first as the default, self-hosted second as the advanced path. First code block swapped from a dual-variant local/hosted snippet to a single hosted-defaultpmxt.Polymarket(pmxt_api_key=...)constructor. - Docs:
authentication.mdxvenue-credentials section reframed — "Hosted writes (recommended)" subsection added on top showing thepmxt_api_key + wallet_address + private_keyconstructor with a one-lineclient.escrow.deposit()example. The raw-private-key prose was preserved but relabeled as "Self-hosted / direct venue credentials (advanced)". Status/body/meaning error table picked up a fourth "SDK exception" column cross-linking to the new/api-reference/errorspage. - Docs:
security.mdx"Run pmxt locally" callout downgraded from<Warning>to<Note>and reworded — self-hosting is positioned as one option among several rather than the implicit "safer choice". PreFundedEscrow custody surfaced as the hosted alternative. - Docs:
sdk/server.mdxgot a top<Note>banner clarifying that the page applies to self-hosted mode only and hosted-mode users can skip it. (File location and slug intentionally not renamed in this release to preserve external links.) - Docs:
concepts/venues.mdxgained a third table at the bottom — "Hosted-trading venues" — listing Polymarket and Opinion with custody type, cross-chain support, and minimum-order-size columns. - READMEs (root, Python, TypeScript): All three flipped to hosted-default. Subtitles, "Why pmxt?" bullets, Quick Start, and Trading sections now lead with
pmxt.Polymarket(pmxt_api_key=...). Per-venue raw-credentials blocks preserved verbatim but moved into "Self-hosted trading (advanced)" subsections. Root README's "No API key required" bullet (actively anti-hosted-positioning) replaced with a "Hosted API" lead bullet. Net +176 lines across the three files.
Fixed
- Core:
Orderschema incore/src/server/openapi.yaml(and the generateddocs/api-reference/openapi.json) now includes the nullabletxHash,chain, andblockNumberfields the SDK has been returning in hosted mode since 2.49.0. Previous spec was silent on these and downstream codegen consumers missed them. - Core:
UserTradeschema gained the sametxHash/chain/blockNumbernullable trio. - Core:
Positionschema —requiredlist trimmed from[marketId, outcomeId, outcomeLabel, size, entryPrice, currentPrice, unrealizedPnL]to[marketId, outcomeId, size]. The other four became optional in 2.49.0 when the SDK stopped fabricating mark-to-market defaults for positions without a known current price; the schema kept claiming they were required, so generated clients with strict-null checking were rejecting valid responses. NewcurrentValuefield added (size * currentPricewhen available).txHash/chain/blockNumberenrichment added. - Core:
Balanceschema gained the optionalvenuefield that hosted-mode responses already carry on multi-venue queries. - Core:
ErrorDetailschema expanded from{ message: string }to the full envelope shipping in production responses —code(with a populated enum covering allHostedTradingErrorcodes plus the pre-existing tree),retryable: boolean, optionalexchange, optional free-formdetailobject. Downstream codegen can now branch oncode.
Docs
docs.json: First-timeredirectsarray added (empty for this release; reserves the structure for future slug renames).
Installation
npm:
npm install pmxtjs@2.49.1
npm install -g @pmxt/cli@2.49.1PyPI:
pip install pmxt==2.49.1Links
What's Changed
- feat(core): openapi schema for hosted-mode enrichment fields (v2.49.1) by @realfishsam in #978
- docs: hosted-default positioning + 11 new pages + READMEs + changelog (v2.49.1) by @realfishsam in #977
Full Changelog: v2.49.0f...v2.49.1f
v2.49.0
Added
- SDK (Python + TypeScript): Hosted trading mode now works end-to-end against
trade.pmxt.dev. Constructing the client with apmxt_api_key/pmxtApiKeyswitches every Group A public method —create_order/createOrder,build_order/buildOrder,submit_order/submitOrder,cancel_order/cancelOrder,fetch_balance/fetchBalance,fetch_positions/fetchPositions,fetch_open_orders/fetchOpenOrders,fetch_my_trades/fetchMyTrades,fetch_order/fetchOrder— to dispatch through PMXT's PreFundedEscrow custody ontrade.pmxt.dev/v0/*instead of the local sidecar. Read methods that require a wallet raiseMissingWalletAddresslocally before any network call when neither an explicitaddressargument norwallet_addresson the client is set.fetch_closed_ordersandfetch_all_ordersraiseNotSupportedin hosted mode (settled orders are modeled as trades; callers should usefetch_my_trades). Both SDKs auto-wrap a rawprivate_key/privateKeyinto the venue signer (EthAccountSignerfor Python viaeth-account,EthersSignerfor TypeScript via the optionalethers >= 6peer dep) so the user never has to construct a signer manually. - SDK (Python + TypeScript): New
Escrownamespace on hosted-mode Polymarket clients (client.escrow.build_approve_tx(...),build_deposit_tx,build_withdraw_tx,withdrawals(...)) for the PreFundedEscrow deposit/withdraw flow. Mirrors the/v0/escrow/*surface; only instantiated on hosted-trading-allowlisted venues. - SDK (Python + TypeScript): New hosted-mode error hierarchy (
HostedTradingError,InsufficientEscrowBalance,OrderSizeTooSmall,InvalidApiKey,OutcomeNotFound,CatalogUnavailable,BuiltOrderExpired,InvalidSignature,NoLiquidity,MissingWalletAddress). Each hosted error keeps a semantic parent so existing catch-sites still work — e.g.InsufficientEscrowBalanceextendsInsufficientFunds,OutcomeNotFoundextendsNotFoundError,CatalogUnavailableextendsExchangeNotAvailable. Python uses true multi-inheritance; TypeScript uses astatic isHostedError = trueflag plus anisHostedError(e)helper to compensate for single-inheritance. The mapper (raise_from_response/raiseFromResponse) translatestrade.pmxt.devstatus codes and detail strings to the right subclass. - SDK (Python): New
tests/e2e/hosted_driver.py— runnable live driver that proves URL routing against prod. Hitstrade.pmxt.dev/v0/*with a deliberately-bogus key so the server returns 401, captures the URL for every public method via anhttpx-level transport hook, and asserts each URL starts withhttps://trade.pmxt.dev/v0/. Also verifies local-only failure paths (MissingWalletAddress,NotSupported,InvalidOrder,InvalidSignature) raise before any network call. - SDK (TypeScript): New
tests/e2e/hosted-driver.ts— equivalent live driver (tsx-runnable) covering the same routing and local-raise assertions, usingglobal.fetchinstrumentation. - SDK (Python + TypeScript): 87 new in-process integration tests (
test_hosted_dispatch.py+test_hosted_error_mapping.pyin Python,hosted-dispatch.test.ts+hosted-error-mapping.test.tsin TypeScript). These mock the lowest reasonable HTTP layer (httpx.MockTransport/jest.spyOn(global, 'fetch')), construct a hosted client, call the public method, and assert exact URL / verb / body shape / response mapping for every Group A method plus the upstream status → SDK exception mapping. - SDK (Python + TypeScript): Feed listing surface on SDK clients — callers can now enumerate available data feeds from the unified client instead of reaching into the internal feed-client submodule. (#869)
Changed
- SDK (Python):
pmxt2.17.1 → 2.18.0. New constructor kwargswallet_address: str | Noneandsigner: Signer | Noneon every Exchange subclass; both are pass-through to the base class. Existing non-hosted (sidecar) callers see no behavior change. - SDK (TypeScript):
pmxtjs2.17.1 → 2.18.0. NewwalletAddress/signer/privateKeyfields onExchangeOptions.ethers >= 6.0.0 < 7.0.0declared as an optionalpeerDependency(only required for hosted writes; hosted reads work without it). - SDK (Python + TypeScript):
Order,UserTrade,Position, andBalancenow carry optionaltx_hash/txHash,chain, andblock_number/blockNumberfields, populated in hosted mode after the trade settles on-chain. Non-hosted callers seeNone/undefinedfor these — unchanged behavior. - SDK (Python + TypeScript):
Positionmark-to-market fields (outcome_label,entry_price,current_price,current_value) are now allOptional. Hosted endpoints populateoutcome_labelandentry_pricefrom operator-side cost-basis enrichment when available, but downstream consumers must handle the missing case rather than relying on fabricated defaults. - SDK (Python + TypeScript): Drift parity sweep across the two SDKs — model shapes, method signatures, capability flags, and generated outputs reconciled so the same call against the same venue returns identically-shaped objects regardless of which SDK you use. (#867)
- SDK (Python + TypeScript): Missing event/order parameters propagated through both SDK models so the full set of fields the core surface produces is actually reachable on the SDK objects. (#872)
- SDK (Python): Type annotations tightened across the Python SDK — narrower union types and
Optionalmarkers replacing implicitAnyin several public signatures. (#868) - Core: Cached exchange specs (the test fixtures used to detect upstream API drift) reconciled with current live payloads from each venue. (#866)
- Core: Magic chain IDs (
137,56, etc.) replaced with named constants throughout the codebase. (#878) - Deps: npm dependency refresh to clear outstanding security advisories. (#864)
- Deps: Python security dependency floors raised to clear outstanding security advisories. (#865)
Fixed
- SDK (Python):
Orderdataclass field ordering —filled_shares: Optional[float] = Nonewas declared before the non-default fieldsremaining: floatandtimestamp: int, which Python 3.13 rejects withTypeError: non-default argument 'remaining' follows default argument 'filled_shares'on first instantiation. Movedfilled_sharesbelow the required fields. - SDK (Python):
_error_detail_from_success_payloadno longer treats a successful 2xx response with a list or scalar JSON payload as an error envelope. Endpoints like/v0/user/{addr}/balancesreturn JSON arrays ([{"currency": "USDC", "amount": 12.5}]); the previous logic stringified the array and re-raised it asHostedTradingError, so every successful read crashed. Only 2xx Mappings with expliciterror/errors/success: falsemarkers now count as an error envelope. - SDK (Python): Duplicate
NotSupportedclass in_hosted_errors.pywas shadowing the canonical one inerrors.py. Tests that didfrom pmxt._hosted_errors import NotSupportedfailed to catch raises fromclient.pythat usedfrom .errors import NotSupported, because the two classes were unrelated._hosted_errors.pynow re-exports the canonicalNotSupportedfromerrors.py. - SDK (TypeScript):
_hostedBuildOrderBodywas writing the user's wallet tobody["wallet_address"], buttrade.pmxt.dev'sBuildOrderV0Reqexpects the field asuser_address. EverycreateOrder/buildOrdervia the TS SDK previously 422-ed on a "missing user_address" Pydantic validation error before reaching the chain. Python SDK was already correct. - SDK (TypeScript): Nine
HOSTED_METHOD_ROUTES.get("…")lookups inclient.tsused snake_case keys ("submit_order","fetch_balance", etc.) against a Map whose keys are camelCase ("submitOrder","fetchBalance", etc.). Every hosted call would have thrownTypeError: Cannot read properties of undefined (reading 'method')at runtime.tscand Jest didn't catch this because the existing unit tests stub out the lookup. Fixed by switching all nine sites to the camelCase keys actually defined in the map. - SDK (TypeScript): Removed the
errors.ts → hosted-errors.tsre-export block that created a circular import.tscandts-jesttolerated the cycle, buttsx/ Node CJS crashed at module load withReferenceError: Cannot access 'PmxtError' before initializationbecauseerrors.ts's body re-exports fromhosted-errors.ts, which extendsPmxtErrordefined later in the sameerrors.tsbody. Hosted error classes are now re-exported once fromindex.tsinstead of viaerrors.ts. The public surface is unchanged for consumers importing frompmxtjs. - Server (Python sidecar): Bare and overly-broad
except:handlers in the sidecar manager tightened to specific exception types, so genuine bugs surface instead of getting swallowed and reported as opaque "server failed to start" errors. Closes #813-#821. (#871) - Server: WebSocket and feed-client hygiene issues surfaced rather than swallowed — disconnects, malformed frames, and feed-side errors now propagate to the caller instead of silently dropping events. (#870)
- Core: Exchange normalizers across all venues realigned with current live payload shapes; addresses cumulative drift that had been quietly producing inconsistent unified objects between SDKs and the server. (#873)
- Kalshi: Pagination capped to prevent unbounded scrolling on
fetchMarkets/fetchEvents, andstatus=allis now serialized as a single value rather than the array form that some Kalshi endpoints reject. (#874) - Limitless: Explicit fetch timeouts on every outbound HTTP call (and the local test server) so a slow upstream can no longer hang the entire SDK request indefinitely. (#875, #876)
- Limitless: Throttler now rejects new work when its queue overflows instead of growing the queue unbounded — prevents memor...
v2.48.6
Fixed
- Opinion:
resolutionDateon Opinion markets no longer collapses to1970-01-01T00:00:00Zwhen the upstreamcutoffAtis missing or0. Root cause:toMillis(0)returned0, which the normalizer then wrapped innew Date(0)and emitted as a valid-looking past date. Categorical child markets (e.g.2026 FIFA World Cup Winner - Spain) are the common case — Opinion publishescutoffAtonly on the parent, not on each child — so every child silently inherited epoch and was filtered out by any downstreamcloses_at > now()guard. Concretely, hosted-pmxt'sfetchMarketMatcheswas dropping all Opinion ↔ Polymarket pairs (407 in the catalog, 13 FIFA-specific) because the Opinion side looked already-closed. - Opinion:
normalizeChildMarketnow inheritsparent.cutoffAtviachild.cutoffAt || parent.cutoffAt, so the fallback introduced in commit6ac8cd1actually fires for thecutoffAt = 0case (the upstream literal, not a missing field). - Core:
toMillis(ts)inopinion/utils.tsnow returnsnullfor falsy input instead of0, so callers can distinguish "no timestamp" from "epoch" and stop materializing bogus 1970 dates. Trade/order normalizers preserve old behavior with?? 0. - Core:
UnifiedMarket.resolutionDateis now?: Date. Not every venue publishes a resolution date on every market, and the optional type lets normalizers emitundefinedinstead of fabricating an epoch sentinel.BaseExchange.filterByCriteriaand the Baozi normalizer handle the optional case (markets without a known resolution date pass anactive-status filter, fail aclosed-status filter, and sort last undersort=newest).
Installation
npm:
npm install pmxtjs@2.48.6
npm install -g @pmxt/cli@2.48.6PyPI:
pip install pmxt==2.48.6Links
Full Changelog: v2.48.5f...v2.48.6f
v2.48.5
Fixed
- Opinion:
outcome.metadataon every market returned byfetchEvents/fetchMarkets/fetchMarketnow carriesopinionMarketId(Opinion's source-native integer market id), mirroring theclobTokenIdshape Polymarket already exposes. Downstream consumers (notablypmxt-trading's/trade/build-order, which keys Opinion orders by integer marketId) can now recover the id from a unified outcome without bypassing pmxt-api. (#838) - Opinion:
fetchMarkets({ marketId })now rejects non-integer values (e.g. accidentally passing a pmxt UUID) with aBAD_REQUESTinstead of silently returning an unrelated market. (#838)
Installation
npm:
npm install pmxtjs@2.48.5
npm install -g @pmxt/cli@2.48.5PyPI:
pip install pmxt==2.48.5Links
Full Changelog: v2.48.4f...v2.48.5f
v2.48.4
Fixed
- Python SDK:
FeedClientis now exported from the top-levelpmxtpackage, sofrom pmxt import FeedClient(andpmxt.FeedClient(...)) work without reaching into the internalpmxt.feed_clientsubmodule. (#835) - TypeScript SDK:
FeedClientis now exported from the top-levelpmxtjspackage alongside its related types (Ticker,Tickers,OHLCV,OracleRound,FeedClientOptions), and is exposed on the defaultpmxtobject. Consumers can nowimport { FeedClient } from 'pmxtjs'or callpmxt.FeedClient(...)directly. (#835)
Installation
npm:
npm install pmxtjs@2.48.4
npm install -g @pmxt/cli@2.48.4PyPI:
pip install pmxt==2.48.4Links
What's Changed
- fix: export FeedClient from Python SDK by @nanookclaw in #835
Full Changelog: v2.48.3f...v2.48.4f