Skip to content
Get an API key

Step zero — from nothing to your first trade

Section titled “Step zero — from nothing to your first trade”
  1. Create the account. Start at xo.market and obtain caller-owned XO CLOB access. XO access is partner-provided; the sources do not document its signup or KYC flow.
  2. Set up credentials. Create the API key, secret, and passphrase in your venue account’s API settings. For the default model, your EVM wallet must own an XO smart account. Secure the wallet seed phrase offline. Predictefy never sees the wallet private key; the credential triple transits Predictefy only for a bounded submit and is never persisted. Known limitation for social-login accounts (2026-08-23): an XO account created via social login is a ZeroDev smart account whose embedded key produces a wrapped ERC-1271 signature — but XO’s POST /order documents the wire signature as exactly 65 bytes, so a bare embedded-key signature is rejected by the venue’s smart-account check and the wrapped form does not fit the documented wire format. Until this is resolved with the venue, trade XO with a wallet-native account (the EOA holds the collateral and signs directly, signatureType 0). Funded verification of the wrapped-signature path is in progress.
  3. Fund it. Hold six-decimal Bridged USDC (XO) on chain 3223, approve the verified exchange, and leave collateral headroom above your first order. No numeric minimum or verified deposit route is published in the allowed sources. If funding crosses chains, query GET /v1/bridge/quote first and use a venue-confirmed route if XO is unsupported.
  4. Allow time. Budget 1–2 hours after CLOB access arrives; partner provisioning can take longer. Predictefy has not yet submitted an XO order; confirm your eligibility.
  • Production status: Building, submitting, and cancelling are all served, rebuilt on 2026-08-18 against the venue’s current order contract. The builder that shipped before that date signed the venue’s previous order struct against its previous exchange and was disarmed the same day; it has been replaced, and the reason to disarm went with it. Nothing has yet been submitted to XO, so the first live submit is the confirmation checkpoint — see the note below.
  • Wallet and chain: An XO smart account on chain 3223 is the default identity, and it is both the order’s maker and its signer. A direct EOA is also accepted; see “Signature models”.
  • Venue account: Use caller-owned XO CLOB access that provides an API key, secret, and passphrase. The lane establishes no separate account-provisioning flow.
  • Credentials: Your signing key stays client-side. The CLOB triple transits only submit, creates HMAC headers in-process, and is never persisted.
  • Funding: Six-decimal Bridged USDC (XO) in the maker account, approved to the verified exchange. There is no hosted helper, and the deposit route remains unverified by the funding registry. Fees are charged in collateral to the maker, so leave a little headroom above the order principal.

XO is a strict server-built lane and has no client-echo compatibility path. It is default off and unregistered: its code and artifact bounds do not mean that any deployment has enabled it. Check GET /v1/exec/venues; an absent XO row is the expected default.

Send asset (the catalog outcome id), or outcome + outcomeSide, with isBuy, price, size, and the owner account. The indexed catalog lookup resolves the outcome first, and XO’s catalog token_id becomes the signed tokenId verbatim.

signatureType selects how the venue validates your signature. 3 is the default and is the XO smart-account model: the account is both maker and signer, and the venue checks the signature through ERC-1271 on that contract, so the 65 bytes you supply come from an owner key of the smart account rather than from the maker address itself. signatureType: 0 is the direct-EOA model, where maker and signer are your own wallet and the venue recovers the signature normally.

The venue’s documentation is not self-consistent here: its authentication and smart-account guides both describe 3 as the only order-signing model the orderbook accepts today, while the order-placement schema documents 0 for direct EOA integrations and lists it in the accepted enum. The default is 3 because that is the model every page agrees on; 0 is available for callers who want it, and is the contested one. The Polymarket proxy models (1 and 2) have no XO identity and are rejected before any venue call.

Orders carry no fee rate. There is no fee field to set or sign; settlement applies the market category’s rate to each filled leg. Predictefy reads that rate from the venue’s public fee endpoint at build time and quotes it with the venue’s documented conviction curve — fee = size × (rate / 10,000) × price × (1 − price), which peaks at a price of 0.5 and falls toward the extremes. The quote assumes a complete fill, so it is an upper bound. The category rate is currently 0, which makes the quote 0 by that formula rather than by assumption; a rate above the exchange’s own on-chain maximum is refused rather than quoted.

expiresAt takes Unix seconds. An explicit 0 is the documented never-expiring GTC opt-in; a future second builds GTD and must be within two years, so a millisecond stamp is rejected rather than signed. Omitting it no longer means GTC: the order expires at the catalog market’s close date when the row carries a future one, bounded by that same two-year horizon, so a resting order cannot outlive the market it was written against. If the catalog has no usable close date, an omitted expiresAt still builds GTC.

The returned artifact includes types, primaryType: "Order", domain, message, and buildVersion: 2. The exact signed fields are salt, maker, signer, beneficiary, tokenId, makerAmount, takerAmount, expiration, nonce, identifier, metadata, side, and signatureType, in that order — thirteen fields; the signature is carried alongside them on the wire but is not part of the hash. beneficiary, identifier, and metadata are always zero-filled by server builds: a zero beneficiary pays the maker, and routing proceeds elsewhere is not a decision this service takes on your behalf. The domain is XO Market CLOB, version 1, chain 3223, verifying contract 0x4bC5E872256D12E6017dfe466E04c867DC761B77. Collateral is six-decimal Bridged USDC (XO), 0x80c12230ce677e6f304027a14780edd2a829ab0c. A missing or stale build version is rejected on both idempotent build replay and submit, before any XO relay — artifacts built by the previous builder carry buildVersion: 1 and are refused rather than relayed.

You sign the complete typed data in your own wallet and submit { executionId, signature, owner, apiKey, apiSecret, apiPassphrase }. Predictefy never receives a private key, never signs, and never persists the credential triple or headers. XO account and funding routes are not implemented.

What the server verifies depends on the signature model, and the difference is real. State it before anything else, because “the server checks your signature” is only true for one of the two:

  • signatureType: 0 (direct EOA). Full binding. The signature must recover to the signer stored at build, against the server-stored digest. A signature that recovers to anyone else is rejected before any venue call.
  • signatureType: 3 (XO smart account — the default). The server cannot bind the signature to an address. The 65 bytes come from an owner key of your smart account, an address this service does not know and has no way to learn, so it checks only that the signature is well-formed. The authority is the venue, which passes the digest and signature to your smart account’s ERC-1271 isValidSignature. That check, on-chain and at the venue, is what accepts or refuses the order.

In both models the server enforces that the owner you submit equals the maker/signer it wrote at build, and it relays only the order it built and stored.

That is why a signature the server cannot bind is still not a route to anyone else’s funds. The order it relays has maker == signer == your own account, pinned at build and re-checked on reload; its beneficiary is the zero address, which pays the maker and nobody else; and the digest is re-derived from the stored order before relay, so the bytes signed and the bytes sent are the same order. A mismatched signature under 3 can at worst cause the venue to execute your own order — or, far more likely, reject it.

After those checks Predictefy reads XO /time, creates the venue’s XO_* L2 HMAC headers in-process, and posts the stored order to /order.

Cancel and a client-credentialed status refresh are served: GET /v1/exec/venues reports cancel: true for XO. They were armed on 2026-08-18, when XO’s own API documentation answered the two questions that had kept them off — every authenticated XO route reads XO_* HMAC header names (not the POLY_* forms this CLOB family uses elsewhere), and a cancel acknowledges with an explicit list of the order ids it removed. They need only the CLOB base URL and your own credentials, never an exchange address or an order struct.

Cancel follows the same non-custodial choreography as an order: POST /v1/exec/xo/orders/{id}/cancel mints a new cancel intent from server-stored truth, and you send that new execution id to /submit with your own apiKey, apiSecret, and apiPassphrase. A cancel carries no signature — XO authenticates it by HMAC alone — and it spends nothing. A status refresh takes the same credential triple and reads your order back from the venue.

A status refresh is also the only way to see a partial fill. A resting order keeps its live status from the first matched share to the last, so the fill shows up as a matched size against the original size rather than as a status change. A submit acknowledgement reports the same thing in its own units when an order matches part way and then rests.

Scope, stated plainly: both routes act on an execution Predictefy already holds — they take an executionId, not a raw venue order id, so they reach XO orders recorded through this service and not orders you placed elsewhere. Cancelling an order placed outside Predictefy is not a route this service offers.

A cancel can legitimately fail, and the venue says so with a 200. XO acknowledges a cancel with the ids it actually removed plus a per-id reason for the ones it did not, so a successful HTTP call can still report failed with a reason such as already filled — the order matched before your cancel arrived. That is a real outcome, not an error in your request. The mapping stays fail-closed in both directions: canceled is reported only when the acknowledgement names your order among the cancelled ids, and any answer we do not recognise is reported as failed with the venue’s own words.