> ## Documentation Index
> Fetch the complete documentation index at: https://pmxt-sync-hosted-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Hosted Trading

> The hosted-default execution path — how PMXT routes orders, the non-custodial PreFundedEscrow, and when to switch to self-hosted.

Hosted trading is PMXT's default execution path. You provide an API key and a wallet; your [USDC](/concepts/prediction-markets-101#usdc) sits in a non-custodial [`PreFundedEscrow`](/concepts/prediction-markets-101#prefundedescrow) smart contract on [Polygon](/concepts/prediction-markets-101#polygon) that can only move funds against an EIP-712 signature from your wallet; orders are built server-side, signed in your browser/server with your private key, and submitted by PMXT to the underlying venue. You never run a local server, never integrate with venue-specific signature schemes, and never expose your private key over the wire.

<Info>
  **One chain to fund: Polygon.** Hosted trading for Polymarket, Opinion,
  and Limitless uses a single Polygon-based `PreFundedEscrow` contract. Fund
  USDC on Polygon once; the same EVM wallet/key can trade the currently hosted
  venues. For non-Polygon hosted venues like Opinion (on BSC) and Limitless
  (on Base), PMXT handles cross-chain settlement transparently — you never
  sign anything on a chain other than Polygon.
</Info>

## When hosted mode is right

Hosted is the right default for:

* **Web and mobile apps** — your backend holds the `pmxt_api_key`; users keep their own private keys on their devices.
* **Trading bots that don't need sub-100ms latency** — typical hosted round-trip is \~150–300ms including the venue submit.
* **Multi-venue strategies** — you stay on one HTTP surface even when you're trading across Polymarket, Opinion, and Limitless.
* **Anyone who doesn't want to operate infrastructure.**

A hosted trade has three actors: **your client** (holding the `pmxt_api_key` and, for writes, the user's `private_key`), **`trade.pmxt.dev`** (PMXT's hosted trading API — routes orders, operates against the escrow contract under user-signed authorization, talks to the venue), and **the venue** (Polymarket's CLOB, Opinion's matching engine, etc. — sees PMXT as the submitter).

Reads (`fetch_balance`, `fetch_positions`, `fetch_my_trades`, etc.) only need the API key and a wallet address. Writes (`create_order`, `cancel_order`) require the user to sign an [EIP-712](/concepts/prediction-markets-101#eip-712) typed-data payload locally.

## The trade flow

```
┌──────────┐  1. POST /v0/trade/build-order   ┌──────────────────┐
│  client  │ ───────────────────────────────► │ trade.pmxt.dev   │
│          │                                  │                  │
│          │  2. unsigned typed-data + id     │                  │
│          │ ◄─────────────────────────────── │                  │
│          │                                  │                  │
│  signs   │ ─── EIP-712 (local only) ────►   │                  │
│          │                                  │                  │
│          │  3. POST /v0/trade/submit-order  │                  │
│          │     { built_order_id, signature }│                  │
│          │ ───────────────────────────────► │                  │
│          │                                  │  4. Venue submit │
│          │  5. order id + status            │ ───────────────► │
│          │ ◄─────────────────────────────── │     (Polygon /   │
└──────────┘                                  │      BSC chain)  │
                                              └──────────────────┘
```

Step-by-step:

1. **Build.** The SDK calls `POST /v0/trade/build-order` with the outcome target, side, and amount. Catalog UUIDs go on the wire as `outcome_id`; venue-native outcomes go on the wire as `venue` + `venue_outcome_id`. The server resolves the venue-native fields (token IDs, salt, expiry, fees), packages them into the venue's EIP-712 typed-data shape, and returns a `built_order_id` plus the payload to sign.
2. **Sign.** The SDK signs the typed-data payload locally with your `private_key`. This step never leaves your process. See [Signing](/guides/signing) for the exact shape.
3. **Submit.** The SDK calls `POST /v0/trade/submit-order` with the `built_order_id` and the signature. The server attaches the signature to the prepared order and submits to the venue.
4. **Settle.** The venue matches the order. Settlement model varies by venue:

   * **Polymarket** — same-chain on Polygon. The user signs one EIP-712 `OrderParams` against the Polygon `PreFundedEscrow` domain. Settlement is direct against the Polymarket CTF exchange. No oracle, no cross-chain hop.
   * **Opinion BUY** — cross-chain Polygon → BSC, **single signature + oracle-attested delivery-versus-payment (DvP)**. The user signs one `CrossChainOrderParams` payload on the Polygon `PreFundedEscrow` domain, authorizing a capped spend of their USDC. The operator fronts BSC working capital, buys on Opinion's CLOB, and calls `depositForUser` on the BSC `VenueEscrow` to credit the user with the real outcome tokens. An independent **settlement oracle** observes the BSC delivery and signs a `DeliveryAttestation`. The operator submits the attestation to `settleCrossChainBuy` on Polygon, which verifies the user signature, the attestation binding (order, user, token, destination escrow), the oracle signature, a non-zero `tokensDelivered`, and a per-token worst-price check before releasing the user's USDC. The operator cannot pull USDC until it has provably delivered tokens. Trust assumption: honest oracle.
   * **Opinion SELL** — cross-chain BSC → Polygon, **dual-signed parallel, no oracle**. The user signs two EIP-712 payloads at build time: a Polygon pay leg (`CrossChainSellPayParams` on the `PreFundedEscrow` domain) and a BSC pull leg (`CrossChainSellPullParams` on the `VenueEscrow` domain). The operator fires both in parallel: `settleCrossChainSellUSDC` credits the user's USDC on Polygon, `settleCrossChainSellTokens` pulls the outcome tokens from the user's BSC escrow. Time-to-tokens is roughly one block. The 2×2 outcome matrix's row 3 (pay failed, pull succeeded) is the operator-trusted gap today; a future bond backstop will close it.
   * **Limitless** — cross-chain Polygon → Base, **v1 signature-gated front-and-reimburse** (ERC-7683). The user signs one ERC-7683 order via EIP-712 on the Polygon escrow domain: "buy ≥Y tokens, debit ≤X USDC, worstPrice, deadline, nonce". The operator fronts Base working capital, buys on Limitless' CLOB, delivers the real tokens to the user's Base escrow, then pulls the capped USDC on Polygon against the signature. **v1 trust asterisk:** the pull is gated by the signature alone, so reimbursement carries a delivery-performance trust point on the operator. v2 will gate the pull on a Base → Polygon delivery proof (UMA optimistic or ZK).

`create_order` is a convenience wrapper that chains build → sign → submit in one call. `build_order` and `submit_order` are the lower-level primitives if you want to inspect or modify the typed-data before signing.

## Catalog UUIDs are the shared address space

Catalog UUIDs are the most portable identifiers for hosted trading. PMXT's catalog assigns a stable UUID to every `prediction_markets.markets` row and every `prediction_markets.outcomes` row, so those IDs are the right choice for Router results, cross-venue analytics, and records you want to survive venue API changes.

Raw REST can use catalog UUIDs or an explicit `venue` + `venue_outcome_id` pair. Bare Polymarket `conditionId` / `tokenId` strings are not enough by themselves; include the venue tuple so the backend can reverse-resolve the catalog row.

The catalog UUIDs are the same ones returned by the Router (`/v0/markets`, `/v0/events`). They are stable across venue API changes and survive venue re-listings.

<Note>
  The SDK accepts either form. Outcomes returned by `pmxt.Polymarket(...).fetch_markets(...)` carry a venue-native ID; outcomes returned by `pmxt.Router(...)` carry a catalog UUID. Pass either straight to `create_order` / `build_order` — the SDK forwards it as `outcome_id` (UUID) or `(venue, venue_outcome_id)` (venue-native) on the wire. Raw REST against `trade.pmxt.dev` follows the same shape. See [Catalog UUID vs venue ID](/concepts/catalog-uuid-vs-venue-id).
</Note>

## Custody: PreFundedEscrow

**Non-custodial by construction** — escrow contracts enforce that funds can only move against an EIP-712 signature from the user's wallet (plus, for cross-chain buys, an oracle attestation). PMXT does not hold USDC in a hot wallet, an exchange-style omnibus account, or a multisig. The user's wallet retains beneficial ownership at all times.

USDC custody lives on **Polygon** in the `PreFundedEscrow` contract (chainId 137, sometimes called `HomeEscrow`). Outcome-token custody on non-Polygon venues lives on the venue's native chain:

* **Polygon `PreFundedEscrow`** holds the user's USDC (USDC.e, `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`) and serves the payment legs for Polymarket, Opinion, and Limitless. Polymarket CTF tokens are custodied here too — same-chain.
* **BSC `VenueEscrow`** (chainId 56) holds Opinion [outcome](/concepts/prediction-markets-101#event-market-outcome) tokens. For Opinion BUYs the operator deposits tokens here on the user's behalf (no user signature on BSC). For Opinion SELLs the user signs a BSC-domain pull leg authorizing the operator to debit this escrow.
* **Base escrow** holds Limitless outcome tokens. The operator delivers tokens here after buying on Limitless' CLOB; the user funds and signs only on Polygon.

USDC enters via `client.escrow.deposit_tx(amount)` on Polygon, exits via `client.escrow.withdraw_tx("request" | "claim" | "cancel", ...)`. Both build unsigned txs — your wallet signs and submits them. See [Escrow Lifecycle](/guides/escrow-lifecycle).

### Deployed contracts

Both contracts are non-upgradeable, non-pausable, with no Ownable role — only an immutable `operator` set at deploy time.

| Contract                       | Chain   | ChainId | Mainnet address                              | Explorer                                                                                  |
| ------------------------------ | ------- | ------- | -------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `PreFundedEscrow` (HomeEscrow) | Polygon | 137     | `0x3ad326f78b1390b9a5dc5f00e7f62f8632de23e2` | [Polygonscan](https://polygonscan.com/address/0x3ad326f78b1390b9a5dc5f00e7f62f8632de23e2) |
| `VenueEscrow`                  | BSC     | 56      | `0x6a273643d84edbb603b808d8a724fb963c7a298a` | [BscScan](https://bscscan.com/address/0x6a273643d84edbb603b808d8a724fb963c7a298a)         |

Current operator addresses (immutable on the deployed contracts above):

* Polygon `PreFundedEscrow.operator`: `0x84194eae9c63C1e3A769976bb762506d3443156d`
* BSC `VenueEscrow.operator`: `0x84194eae9c63C1e3A769976bb762506d3443156d`
* Polygon `PreFundedEscrow.settlementOracle`: `0x8aD93c0D15bC655b460dD700B1E25C86D1a728EE`

The operator address is an EOA controlled by PMXT. Because `operator` is `immutable` on the deployed contracts, switching to a multisig would mean deploying new escrow contracts and migrating user balances — not an in-place rotation.

### Trust model

There is no admin. The contracts have **no `Ownable`, no `Pausable`, no upgrade proxy, no upgrade timelock, no fee setter**. The privileged surface is the `onlyOperator` modifier in the shared `OutcomeCustody` base contract, and the `operator` address is `immutable` — set once in the constructor and unchangeable for the life of the contract.

What this means concretely:

* **No one can pause withdrawals.** Even if PMXT's operator key is compromised, `withdraw` / `claimWithdrawal` keep working — unilateral withdrawal is always available, even if PMXT's server is down.
* **No one can change the operator.** A compromised PMXT cannot rotate to a new operator and skip user signatures.
* **No one can upgrade the contract.** What's deployed is what runs forever.

Every value-moving operator call requires either the user's EIP-712 signature, the user as `msg.sender`, or (for cross-chain buys) an additional delivery attestation signed by an independent settlement oracle. The `pmxt_api_key` is a **service-role credential**: the key holder can read any associated wallet's hosted data and forward signed orders, but **the key alone cannot move funds**. Keep `pmxt_api_key` on a server. Never ship it to a browser bundle. Never log it.

### Audit status

**Unaudited as of 2026-06-09.** The contracts have not undergone a third-party security review. The contract is non-pausable and unilateral withdrawal is always available — if you want to exit, the timelock is your kill-switch and PMXT cannot block it. An audit report will be linked here when one is completed.

## When to switch to self-hosted

Self-hosted runs `pmxt-core` on your own machine; the SDK talks to `localhost`.
Both modes use the same SDK classes and method names where the capability is
supported. The differences are where execution happens, who holds keys, and
which write venues each mode supports.

|                           | Hosted (`pmxt_api_key` set)                                                           | Self-hosted (no API key)                             |
| ------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| **Install footprint**     | `pip install pmxt` / `npm i pmxtjs`                                                   | SDK + pmxt-core local server                         |
| **Trading auth (writes)** | Your EIP-712 signature, signed locally                                                | Raw venue credential (private key, Kalshi RSA, etc.) |
| **Reads**                 | `trade.pmxt.dev/v0/user/...`                                                          | Direct to the venue API                              |
| **Writes**                | `trade.pmxt.dev/v0/trade/{build,submit}-order`                                        | Direct to the venue API                              |
| **Custody**               | Non-custodial: USDC in `PreFundedEscrow`, movable only against your EIP-712 signature | You retain venue-native custody                      |
| **Latency**               | \~150–300ms round-trip                                                                | Limited by venue + your network                      |
| **Trading venues**        | Polymarket, Opinion, Limitless                                                        | Venues with venue-native write support               |
| **Read-only venues**      | All catalog venues via Router                                                         | All catalog venues via Router                        |
| **Infra to run**          | None                                                                                  | One local process                                    |
| **Regulatory posture**    | Non-custodial escrow; user retains beneficial ownership and unilateral withdrawal     | You as direct counterparty to the venue              |

Choose self-hosted when you need **sub-100ms latency**, want to use **raw venue credentials** (Polymarket L2 API keys, Kalshi RSA, Smarkets sessions), have **regulatory requirements** that mandate direct counterparty status with the venue, or want venue-native trading where the venue exposes writes but hosted mode does not. See [Self-hosted](/guides/self-hosted) for setup.

## What's supported today

| Venue                                               | Hosted writes | Hosted reads          | Notes                                                                                                                                                                               |
| --------------------------------------------------- | ------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Polymarket                                          | Yes           | Yes                   | Polygon escrow, CLOB exchange                                                                                                                                                       |
| Opinion                                             | Yes           | Yes                   | Cross-chain (BSC settlement, dual-signature)                                                                                                                                        |
| Limitless                                           | Yes           | Yes                   | Polygon buy leg, Base pull-sell leg                                                                                                                                                 |
| Kalshi, Smarkets, Probable, Myriad, Metaculus, etc. | No            | Read-only via catalog | Use [self-hosted](/guides/self-hosted) for venue-native writes where supported; check [Feature Support & Compliance](https://github.com/pmxt-dev/pmxt/blob/main/core/COMPLIANCE.md) |

If a venue you need isn't here and it exposes writes, run pmxt-core locally and pass raw venue credentials — see [Self-hosted](/guides/self-hosted).

## Next

* [Trading quickstart](/trading-quickstart) — 60-second guided path.
* [Escrow lifecycle](/guides/escrow-lifecycle) — deposits, withdrawals, the timelock.
* [Hosted errors](/guides/hosted-errors) — every error class and how to recover.
