Audited against Polymarket/py-clob-client-v2 commit a2ec069fb66096e2b80ff0b7fdf628fc41d6352c.

This file tracks CLOB HTTP endpoint coverage in polymarket_clob. It intentionally does not cover WebSockets, bot integration, the higher-level SDK, or strategy code.

Private GET requests in this package sign the base endpoint path and send query params only on the URL. This matches the audited Python client behavior for L2-authenticated GETs.

Coverage Summary

BucketCount
Implemented (public market data)25
Implemented (private account/data, L2 GET/POST/DELETE)13
Implemented (private order management, L2 POST/DELETE)6
Total implemented44
Not yet implemented (private account/key management, mixed L1/L2)6
Total not yet implemented6
Intentionally skipped (local helpers / composed)3
Intentionally skipped (rewards)6
Intentionally skipped (builder surface)6
Intentionally skipped (RFQ)9
Total intentionally skipped24
Total Python v2 surface enumerated74

Scope

This document covers the CLOB HTTP endpoint surface wrapped by the Elixir API modules under PolymarketClob.API.*. Each implemented row maps a Python method on Polymarket/py-clob-client-v2 to the Elixir wrapper that calls the same path with the same authentication scope.

Out of Scope For This Document

  • WebSockets — neither the CLOB market channel (wss://ws-subscriptions-clob.polymarket.com/ws/market), the user channel, nor the RTDS feed (wss://ws-live-data.polymarket.com) are HTTP endpoints, and py-clob-client-v2 does not own them. WebSocket coverage will be tracked separately when those modules land.
  • L1 (EIP-712 ClobAuth) endpoints/auth/api-key (POST), /auth/derive-api-key (GET), and the readonly-API-key family are listed under "Not Yet Implemented" but require Auth.L1 to grow request-side helpers and a credential-lifecycle decision before they can be wrapped. The L1 auth primitive itself is implemented and fixture-backed; only the endpoint wrappers built on top of it are missing.
  • Signing and order-building primitivesAuth.L1 (ClobAuth with nonce), Auth.L2 (HMAC), EIP712, Order.Builder (limit + market amounts, signed-order construction), Order.Signing (EIP-712 domain, hashing, signature), and Order.Rounding (price/size/amount decimal config) are documented in README.md, AGENTS.md, and PACKAGE_PLAN.md, and are validated by parity fixtures under test/fixtures/parity/. They are listed here only as cross-reference; correctness changes for them belong in those files.
  • Higher-level SDK behavior (polymarket package) — Gamma, Data API, RTDS, CTF redeem/merge/split, pUSD wrap/unwrap, P&L helpers, activity normalization. The audited Python client does not own these either.

Implemented Endpoints

Public status and market data

Python methodElixir wrapperMethodPathBody/query notes
get_okMarketData.ok/1GET/okNo body or query.
get_versionMarketData.version/1GET/versionNo body or query.
get_server_timeMarketData.server_time/1GET/timeNo body or query.
get_marketsMarketData.get_markets/2GET/marketsQuery params passed through. Python uses next_cursor.
get_simplified_marketsMarketData.get_simplified_markets/2GET/simplified-marketsQuery: next_cursor.
get_sampling_marketsMarketData.get_sampling_markets/2GET/sampling-marketsQuery: next_cursor.
get_sampling_simplified_marketsMarketData.get_sampling_simplified_markets/2GET/sampling-simplified-marketsQuery: next_cursor.
get_marketMarketData.get_market/2GET/markets/:condition_idPath segment.
get_clob_market_infoMarketData.get_clob_market_info/2GET/clob-markets/:condition_idPath segment.
get_market_by_tokenMarketData.get_market_by_token/2GET/markets-by-token/:token_idPath segment.
get_market_trades_eventsMarketData.get_market_trades_events/2GET/markets/live-activity/:condition_idPublic path segment.
get_order_bookMarketData.get_order_book/2GET/bookQuery: token_id.
get_order_booksMarketData.get_order_books/2POST/booksBody is caller-provided list.
get_tick_sizeMarketData.get_tick_size/2GET/tick-sizeQuery: token_id.
get_neg_riskMarketData.get_neg_risk/2GET/neg-riskQuery: token_id.
get_fee_rate_bpsMarketData.get_fee_rate/2GET/fee-rateQuery: token_id; exposed as legacy fee-rate response.
get_midpointMarketData.get_midpoint/2GET/midpointQuery: token_id.
get_midpointsMarketData.get_midpoints/2POST/midpointsBody is caller-provided list.
get_priceMarketData.get_price/3GET/priceQuery: token_id, side.
get_pricesMarketData.get_prices/2POST/pricesBody is caller-provided list.
get_spreadMarketData.get_spread/2GET/spreadQuery: token_id.
get_spreadsMarketData.get_spreads/2POST/spreadsBody is caller-provided list.
get_last_trade_priceMarketData.get_last_trade_price/2GET/last-trade-priceQuery: token_id.
get_last_trades_pricesMarketData.get_last_trades_prices/2POST/last-trades-pricesBody is caller-provided list.
get_prices_historyMarketData.get_prices_history/2GET/prices-historyQuery names: market, startTs, endTs, fidelity, interval.

Private account and user data

Python methodElixir wrapperMethodPathBody/query notes
get_api_keysAccount.get_api_keys/2GET/auth/api-keysL2-authenticated; no body or query.
get_closed_only_modeAccount.get_closed_only_mode/2GET/auth/ban-status/closed-onlyL2-authenticated; no body or query.
get_orderAccount.get_order/3GET/data/order/:order_idL2-authenticated path segment.
get_open_ordersAccount.get_open_orders/3GET/data/ordersQuery passed through; Python auto-paginates by default, Elixir is a direct page wrapper.
get_pre_migration_ordersAccount.get_pre_migration_orders/3GET/data/pre-migration-ordersQuery passed through; Python auto-paginates by default, Elixir is a direct page wrapper.
get_tradesAccount.get_trades/3GET/data/tradesQuery passed through; Python auto-paginates by default, Elixir is a direct page wrapper.
get_trades_paginatedAccount.get_trades_paginated/3GET/data/tradesSame path as get_trades; exposes the Python paginated-name alias. Direct page wrapper.
is_order_scoringAccount.is_order_scoring/3GET/order-scoringL2 GET. Query: optional order_id.
are_orders_scoringAccount.are_orders_scoring/3POST/orders-scoringL2 POST. Body: JSON array of order IDs.
get_notificationsAccount.get_notifications/2GET/notificationsQuery: signature_type.
drop_notificationsAccount.drop_notifications/3DELETE/notificationsQuery: optional ids, comma-joined; no body.
get_balance_allowanceAccount.get_balance_allowance/3GET/balance-allowanceQuery: signature_type, optional asset_type, token_id.
update_balance_allowanceAccount.update_balance_allowance/3GET/balance-allowance/updateWrite modeled by Python as GET. Query: signature_type, optional asset_type, token_id.

Private order management

Python methodElixir wrapperMethodPathBody/query notes
post_orderOrders.post_order/3POST/orderElixir accepts an already-built signed order payload; it does not build/wrap the order.
post_ordersOrders.post_orders/3POST/ordersElixir accepts already-built signed order payloads; it does not build/wrap the orders.
cancel_orderOrders.cancel_order/3DELETE/orderBody: {"orderID": id}.
cancel_ordersOrders.cancel_orders/3DELETE/ordersBody: list of order IDs/hashes.
cancel_allOrders.cancel_all/2DELETE/cancel-allNo body or query.
cancel_market_ordersOrders.cancel_market_orders/3DELETE/cancel-market-ordersBody: optional market, asset_id; field order mirrors Python.

Not Yet Implemented

These endpoints exist in the audited Python client and are plausible future polymarket_clob work, but they have not been wrapped yet.

Private account/key management

Python methodMethodPathBody/query notes
create_api_keyPOST/auth/api-keyL1-authenticated; no body.
derive_api_keyGET/auth/derive-api-keyL1-authenticated; no body.
delete_api_keyDELETE/auth/api-keyL2-authenticated; no body.
create_readonly_api_keyPOST/auth/readonly-api-keyL2-authenticated; no body.
get_readonly_api_keysGET/auth/readonly-api-keysL2-authenticated; no body.
delete_readonly_api_keyDELETE/auth/readonly-api-keyBody: {"key": key}.

Intentionally Skipped For Now

These are deliberately outside the current low-level endpoint-wrapper slices.

Local helper/composed behavior

Python method/groupMethodPathBody/query notesReason
create_order, create_market_ordern/an/aLocal builder helpers.Local order builders already exist; no HTTP endpoint.
create_and_post_order, create_and_post_market_orderPOST/orderComposes metadata resolution, building, and posting.Current Elixir keeps building and posting separate.
calculate_market_price, get_order_book_hash, fee/tick/neg-risk cache helpersn/an/aLocal calculation/cache behavior.Not endpoint wrappers.

Rewards

Python methodMethodPathBody/query notesReason
get_current_rewardsGET/rewards/markets/currentQuery: next_cursor; Python auto-paginates.Reward reporting may belong in the higher-level SDK.
get_raw_rewards_for_marketGET/rewards/markets/:condition_idQuery: next_cursor; Python auto-paginates.Reward reporting may belong in the higher-level SDK.
get_earnings_for_user_for_dayGET/rewards/userL2 GET. Query: date, signature_type, next_cursor; Python auto-paginates.Reward reporting may belong in the higher-level SDK.
get_total_earnings_for_user_for_dayGET/rewards/user/totalL2 GET. Query: date, signature_type.Reward reporting may belong in the higher-level SDK.
get_user_earnings_and_markets_configGET/rewards/user/marketsL2 GET. Query: date, signature_type, next_cursor, order_by, position, no_competition; Python auto-paginates.Reward reporting may belong in the higher-level SDK.
get_reward_percentagesGET/rewards/user/percentagesL2 GET. Query: signature_type.Reward reporting may belong in the higher-level SDK.

Builder surface

Python methodMethodPathBody/query notesReason
post_heartbeatPOST/v1/heartbeatsL2 POST. Body: {"heartbeat_id": heartbeat_id}.Builder/service heartbeat behavior, not standard trading/account CLOB usage.
create_builder_api_keyPOST/auth/builder-api-keyL2 POST; no body.Builder credential lifecycle needs product decisions.
get_builder_api_keysGET/auth/builder-api-keyL2 GET; no body or query.Builder credential lifecycle needs product decisions.
revoke_builder_api_keyDELETE/auth/builder-api-keyL2 DELETE; no body.Builder credential lifecycle needs product decisions.
get_builder_tradesGET/builder/tradesL2 GET. Query includes builder_code, optional filters, and next_cursor.Builder attribution/query model needs product decisions.
__ensure_builder_fee_rate_cachedGET/fees/builder-fees/:builder_codePublic GET path segment used by Python cache helper.Builder fee lookup should be designed with builder order support.

RFQ

Python methodMethodPathBody/query notesReason
create_rfq_requestPOST/rfq/requestL2 POST. Body includes assetIn, assetOut, amountIn, amountOut, userType; Python resolves tick size and rounds first.RFQ is a distinct product surface.
cancel_rfq_requestDELETE/rfq/requestL2 DELETE. Body: {"requestId": request_id}.RFQ is a distinct product surface.
get_rfq_requestsGET/rfq/data/requestsL2 GET. Query is parsed from RFQ request filters.RFQ is a distinct product surface.
create_rfq_quotePOST/rfq/quoteL2 POST. Body includes requestId, assets, amounts, and userType; Python resolves tick size and rounds first.RFQ is a distinct product surface.
cancel_rfq_quoteDELETE/rfq/quoteL2 DELETE. Body: {"quoteId": quote_id}.RFQ is a distinct product surface.
get_rfq_requester_quotesGET/rfq/data/requester/quotesL2 GET. Query parsed from RFQ quote filters.RFQ is a distinct product surface.
get_rfq_quoter_quotesGET/rfq/data/quoter/quotesL2 GET. Query parsed from RFQ quote filters.RFQ is a distinct product surface.
get_rfq_best_quoteGET/rfq/data/best-quoteL2 GET. Query: optional requestId.RFQ is a distinct product surface.
accept_rfq_quotePOST/rfq/request/acceptL2 POST. Python fetches quote data and builds a V1 signed order internally.Conflicts with endpoint-wrapper-only design.
approve_rfq_orderPOST/rfq/quote/approveL2 POST. Python fetches quote data and builds a V1 signed order internally.Conflicts with endpoint-wrapper-only design.
rfq_configGET/rfq/configL2 GET; no body or query.RFQ is a distinct product surface.

Product/Domain Decisions Needed

  • API key lifecycle: decide whether polymarket_clob should create/delete user API keys, or only consume provided credentials. These endpoints mutate credentials and use both L1 and L2 auth.
  • Readonly API keys: decide whether readonly key management belongs in the low-level CLOB package or a higher-level administration surface.
  • Reward reporting: decide whether rewards are low-level CLOB data or part of the higher-level Polymarket SDK.
  • Builder surface: decide how builder codes, builder API keys, builder trades, fee lookup, and heartbeat should be modeled before wrapping these endpoints.
  • RFQ: decide whether RFQ should be a separate module/package boundary. Python RFQ accept/approve paths build V1 orders internally, which conflicts with the current endpoint-wrapper-only design.
  • Pagination shape: decide whether Elixir should add Python-style auto-pagination helpers in addition to direct page wrappers for open orders, trades, rewards, and market lists.

Pagination Policy

Wrappers that the Python client auto-paginates by default — get_open_orders, get_trades, get_pre_migration_orders, and the cursored market-list endpoints — are exposed in Elixir as direct page wrappers. The caller passes :next_cursor (and any filter params) and receives the raw page body. Auto-pagination is intentionally not provided yet because:

  • The streaming consumer pattern in Elixir is typically a Stream.resource/3, not a loop that accumulates a list. Adding Enumerable-friendly cursors is a design choice that may belong in the higher-level polymarket SDK.
  • Bot/SDK callers may want the cursor exposed for state persistence (resumable backfills), which an opaque auto-paginator would hide.

If/when auto-pagination is added, the direct page wrappers should remain so callers that need cursor visibility are not forced through a wrapper.

Maintenance

When Polymarket/py-clob-client-v2 advances:

  1. Update the audited commit hash in this document's header.
  2. Diff the new commit against the audited commit, focusing on client.py, endpoints.py, and any new modules under py_clob_client/.
  3. For each new public method, add a row to Implemented, Not Yet Implemented, or Intentionally Skipped with a one-sentence rationale.
  4. For each removed/renamed method, update both this document and the corresponding Elixir wrapper.
  5. Re-run mix test to verify parity fixtures still match (test/fixtures/parity/{clob_auth,l2_hmac,order_builder,orders}.json are the load-bearing ones; regenerate via scripts/generate_parity_fixtures.py if the Python client's signing/auth output changed).
  6. Update the Coverage Summary counts at the top of this document.

This document is the single source of truth for HTTP endpoint coverage. Anything beyond that — auth primitives, signing, order building, WebSockets, higher-level SDK — is documented in README.md, AGENTS.md, PACKAGE_PLAN.md, or the relevant module moduledoc.