# How to place a prediction market order from code

Five clients that actually submit orders, and the three things between a working script and a fill — the key, the wallet approvals and the eligibility check.

*https://predictionmarkets.tools/how-to/place-an-order-from-code · next to Trading Clients, SDKs & Bots*

**Answer:** Pick the venue first, because there is no portable order. Kalshi has an official generated Python client and a better third-party one; Polymarket has its own SDK for the on-chain exchange and a separate one for the US exchange, which share nothing; Limitless publishes its own async client. The library is the easy part. The credential, the wallet approvals and whether you may place an order at all are the rest.

## The approaches, in order

1. [Kalshi Python SDK (sync and async)](https://predictionmarkets.tools/tools/kalshi-python-sync.md) — Kalshi's current official client, regenerated from the OpenAPI spec on a weekly cadence. REST only, Python 3.13 or newer, no public source.
2. [pykalshi](https://predictionmarkets.tools/tools/pykalshi.md) — The MIT third-party Kalshi client with what the generated one leaves out — WebSocket streaming, a local order book, retries and typed errors.
3. [polymarket-client](https://predictionmarkets.tools/tools/polymarket-client.md) — Polymarket's own SDK for the on-chain exchange, with reads and trading split across separate classes so a price script never holds key material.
4. [Polymarket US Python SDK](https://predictionmarkets.tools/tools/polymarket-us-python.md) — The US exchange from Python. An Ed25519 exchange credential rather than a wallet key, and none of the on-chain approval steps in the way.
5. [limitless-sdk](https://predictionmarkets.tools/tools/limitless-sdk.md) — Limitless's own async client, signing CLOB and NegRisk orders in process; its README asks builders to check their location before placing one.

*Ordered editorially. Paid placement does not affect this order.*

## The short way

Pick the venue, then the client. There is no portable order here: Kalshi and Polymarket are
unrelated systems with different identifiers, different price units, different signing schemes and
different answers to who may place an order at all.

For Kalshi, [the current official Python SDK](https://predictionmarkets.tools/tools/kalshi-python-sync) is
`kalshi_python_sync` or `kalshi_python_async` — not the older `kalshi-python` package, which
Kalshi's own documentation marks as deprecated. For Polymarket's on-chain exchange,
[polymarket-client](https://predictionmarkets.tools/tools/polymarket-client) is the package Polymarket's documentation names, and
the import is `polymarket` rather than the distribution name. For
[Polymarket US](https://predictionmarkets.tools/tools/polymarket-us-python) it is a different SDK entirely, against a different
host, with a different credential.

The credential comes out of the environment, never out of the file:

```bash
# Kalshi: the API key id, plus the path to the RSA private key it was registered against.
export KALSHI_API_KEY_ID="..."
```

## What the options are

**Kalshi, official.** Seventeen API modules covering markets, events, orders, order groups,
portfolio, historical and live data, generated from the OpenAPI specification and released on a
weekly cadence — thirty-one versions since December 2025. Authentication is an API key id plus an
RSA private key, with RSA-PSS request signing. Two things to know before you plan around it: it
requires **Python 3.13 or newer**, which rules out most production images in use today, and it
ships no WebSocket at all, because the streaming half of the Kalshi API lives in a separate
specification.

**Kalshi, third-party.** [pykalshi](https://predictionmarkets.tools/tools/pykalshi) is MIT and exists largely because of that
gap: an `OrderbookManager` that applies the WebSocket deltas and hands back the current book,
automatic retries, pandas output, typed exceptions, Python 3.9 and up, and five runtime
dependencies a person can actually check. It reads `KALSHI_API_KEY_ID` and a path to your key file
from the environment and signs in process. It is one person's library, it does not cover the whole
API by its own admission, and it learns about an API change when something breaks.

**Polymarket, on-chain.** polymarket-client ships four clients, and the split is the useful part:
`PublicClient` and `AsyncPublicClient` need no credentials at all, while `SecureClient` and
`AsyncSecureClient` take a local private key and can trade. `SecureClient.create()` derives the
Level 2 API credentials and the wallet address from the signer key, classifies the account as a
plain EOA, a Polymarket proxy, a Gnosis Safe or a Deposit Wallet, and picks the signature type from
that. Orders are EIP-712 typed data signed in your process; the package posts signatures rather
than credentials.

**Polymarket, US.** [polymarket-us-python](https://predictionmarkets.tools/tools/polymarket-us-python) is a thinner, different
animal: `httpx` for transport, `pynacl` for Ed25519 signing, sync and async clients, and a
credential that is an exchange API key id plus a base64-encoded Ed25519 secret. There is no wallet
key and no on-chain signing, because the US exchange settles in dollars — which removes the whole
class of approval failures below, and adds an identity check instead.

**Limitless.** [limitless-sdk](https://predictionmarkets.tools/tools/limitless-sdk) is async throughout, on `aiohttp` and
`python-socketio`, with GTC, FAK and FOK orders on both the CLOB and NegRisk multi-outcome markets,
signed locally with `eth-account` against a cached copy of the venue contract addresses. It is one
of the few official venue clients here whose last release and last commit are the same day.

## Where this breaks

**The key is three different objects wearing one word.** An RSA private key registered against a
Kalshi account, used to sign each request. An Ed25519 secret issued from a developer page on a
Polymarket US account. And, on the on-chain venues, a Polygon signing key which is the key that can
move the collateral — there is no read-only version of it to hand over.
[Where your key lives when software trades for you](https://predictionmarkets.tools/guides/where-your-key-lives) is the page for
that decision rather than a paragraph here. The practical rule from the cards: prefer a library
that separates reading from trading the way polymarket-client does in its type system, and know
which of the three you are handing over.

**The wallet and its approvals are work, and they are where a first order actually fails.** On
Polymarket the allowance step used to be a linked gist; polymarket-client now carries
`approve_erc20`, `approve_erc1155_for_all`, `get_trading_approvals_state`, a gasless relayer path
and `split_position`, `merge_positions` and `redeem_positions` inside the library. On-chain
operations still cost gas. Polymarket US has none of this, which is the single largest difference
between two SDKs published by the same vendor.

**The eligibility check is not in the library and cannot be worked around by it.** The limitless-sdk
README states that Limitless restricts order placement from US locations for regulatory and
sanctions reasons and asks builders to check their location before placing an order — reading is
not what is restricted, placing an order is. Polymarket US issues API keys only from the developer
page of an account that has completed identity verification, and that gate sits on the WebSocket
streams as well as on the writes.
[What you have to prove about yourself to trade](https://predictionmarkets.tools/guides/what-you-have-to-prove-to-trade) is where
that whole question lives.

**The package a search result gives you is archived.**
[py-clob-client](https://predictionmarkets.tools/tools/py-clob-client) is MIT, archived, and carries Polymarket's own notice that
it is no longer functional and should not be used for new or existing integrations. The PyPI page
carries no warning at all, so the install succeeds with nothing to tell you. The replacement is
polymarket-client. Two other names on PyPI make this worse: the bare `polymarket` distribution is
an unrelated 2024 package and `polymarket-sdk` is an unrelated 2026 one, and both install cleanly.
[Which Python client to write against Polymarket](https://predictionmarkets.tools/compare/polymarket-python-clients) is the head
to head.

**A 200 is not always a fill.** On Polymarket US the per-entry outcome of a batch create is
delivered on the private order stream rather than in the HTTP response, and `canceledOrderIds` is
an echo of the request rather than a confirmation — if you are not holding the socket, you do not
know what happened. [Tools with a streaming feed](https://predictionmarkets.tools/collections/streaming-feeds) covers which
venues put what on which channel.

## If you outgrow this

If the strategy needs more than one venue, [CCXT](https://predictionmarkets.tools/tools/ccxt) and [PMXT](https://predictionmarkets.tools/tools/pmxt) are the two
abstractions in this catalogue, and [tools that cover more than one venue](https://predictionmarkets.tools/collections/cross-venue)
is the listing with what each of them flattens to get there.

And before writing the loop that runs it unattended, read
[what running a bot does not solve](https://predictionmarkets.tools/guides/what-a-bot-cannot-fix). The things that break a
production order path are rate limits, trading hours, a market clarification changing the question
under an open position, and resolution taking days — none of which is a property of the client you
picked above.

## FAQ

### Is there one library that places orders on every venue?

Two try. CCXT implements order placement across all seven venues in its prediction namespace, and PMXT covers hosted writes on Polymarket, Opinion and Limitless with Kalshi writes needing its self-hosted path. Both cost you exchange-shaped errors in exchange for one vocabulary, and neither removes the per-venue credential, approval or eligibility work below.

### Can I test an order without real money?

On Kalshi, yes — it runs a full demo environment on separate hosts with separate credentials, which is the only sandbox in this catalogue. pykalshi has no paper mode of its own and wiring it to the demo is your job. Limitless states plainly that there is no sandbox, no testnet and no mock mode, and suggests minimum-size live orders on a low-volume market instead.

### Why does pip install py-clob-client still work?

Because PyPI carries no warning even though the repository does. py-clob-client is archived and its README says the client is no longer functional and should not be used for new or existing integrations; the migration target is polymarket-client. The install succeeds today with nothing to tell you, which is why it is still the answer most search results give.

### Does the SDK ever see my private key?

On the on-chain venues it holds it in process to sign locally, which is the design rather than a lapse — polymarket-client and limitless-sdk both build and sign the payload in your program and post the signature. On the US exchange there is no wallet key at all — the credential is an exchange API key id plus a base64-encoded Ed25519 secret, issued from a developer page.

## Sources

1. [Python quickstart](https://docs.polymarket.com/getting-started/python) — Polymarket, read 2026-09-19
2. [kalshi-python-sync project page](https://pypi.org/project/kalshi-python-sync/) — Python Package Index, read 2026-09-19
3. [limitless-sdk repository](https://github.com/limitless-labs-group/limitless-sdk) — Limitless Exchange, read 2026-09-21
4. [Environments](https://docs.polymarket.us/trader-guide/environments) — Polymarket US, read 2026-09-21

*Last updated 2026-09-21. A reference page, corrected in place — not a dated post.*
