Client for the Polymarket CLOB REST API (https://clob.polymarket.com).
The base URL defaults to production but can be pointed at another deployment —
e.g. the staging host https://clob-staging.polymarket.com — with:
config :ex_polymarket, :clob_url, "https://clob-staging.polymarket.com"Remember to match the chain id to the deployment when authenticating: 137
(Polygon) for production, 80002 (Amoy) for the testnet.
Summary
Functions
Creates new CLOB API credentials for this wallet.
Creates new credentials, falling back to deriving existing ones.
Derives this wallet's existing CLOB API credentials.
Resolves a token ID to its parent market.
Returns the current server time as a Unix timestamp (seconds since the epoch).
Returns the current server time as a UTC DateTime.
Submits a caller-constructed, already-signed order to POST /order.
Submits a batch of caller-constructed, already-signed orders to POST /orders.
Functions
@spec create_api_key(Polymarket.Crypto.private_key(), integer(), keyword()) :: {:ok, Polymarket.Schemas.Credentials.t()} | {:error, :create_api_key_failed}
Creates new CLOB API credentials for this wallet.
Signs an L1 ClobAuth message with private_key and calls
POST /auth/api-key, returning freshly minted credentials. Accepts the same
opts as derive_api_key/3.
@spec create_or_derive_api_key(Polymarket.Crypto.private_key(), integer(), keyword()) :: {:ok, Polymarket.Schemas.Credentials.t()} | {:error, :derive_api_key_failed}
Creates new credentials, falling back to deriving existing ones.
Mirrors the reference client: tries create_api_key/3 first and, if it fails
(e.g. the wallet already has a key), returns derive_api_key/3 instead. Accepts
the same opts as those functions.
@spec derive_api_key(Polymarket.Crypto.private_key(), integer(), keyword()) :: {:ok, Polymarket.Schemas.Credentials.t()} | {:error, :derive_api_key_failed}
Derives this wallet's existing CLOB API credentials.
Signs an L1 ClobAuth message with private_key (see Polymarket.Clob.ClobAuth)
and calls GET /auth/derive-api-key, returning the deterministic credentials the
CLOB has already associated with the wallet's address on chain_id (137 Polygon
/ 80002 Amoy).
opts accepts :nonce (the API-key slot, default 0) and :timestamp (Unix
seconds, default the current system time).
@spec get_market_by_token(String.t()) :: {:ok, Polymarket.Schemas.MarketByToken.t()} | {:error, :get_market_by_token_failed}
Resolves a token ID to its parent market.
Returns the market's condition_id and both token IDs for the given
token_id. Useful when you have a token ID but not the condition ID.
Examples
Polymarket.Clob.get_market_by_token("71321045679252212594626385532706912750332728571942532289631379312455583992563")
@spec get_server_time() :: {:ok, integer()} | {:error, :get_server_time_failed}
Returns the current server time as a Unix timestamp (seconds since the epoch).
Useful for synchronising a local clock with the CLOB server before signing time-sensitive requests. The endpoint returns the timestamp as a bare value (a JSON string in practice) rather than an object; it is parsed into an integer.
Examples
Polymarket.Clob.get_server_time()
#=> {:ok, 1234567890}
@spec get_server_time_utc() :: {:ok, DateTime.t()} | {:error, :get_server_time_failed}
Returns the current server time as a UTC DateTime.
Convenience wrapper around get_server_time/0 that converts the Unix timestamp
(seconds since the epoch) into a DateTime in the Etc/UTC time zone.
Examples
Polymarket.Clob.get_server_time_utc()
#=> {:ok, ~U[2009-02-13 23:31:30Z]}
@spec post_order( Polymarket.Schemas.SendOrder.t(), Polymarket.Schemas.Credentials.t(), keyword() ) :: {:ok, Polymarket.Schemas.SendOrderResponse.t()} | {:error, Polymarket.Schemas.ClobError.t()}
Submits a caller-constructed, already-signed order to POST /order.
Takes a Polymarket.Schemas.SendOrder — the exact CLOB request payload, which the
caller builds: sign the order with Polymarket.Clob.OrderSigner, fold the
signature in, and set owner/order_type/flags. This function only serialises it,
authenticates the request with L2 HMAC headers derived from credentials, and
posts it.
credentials must come from the auth functions (so its address — the api-key
owner EOA — is populated); that address is sent as the POLY_ADDRESS header.
Note this is the signing wallet, not the order's maker/signer (which, for a
:poly1271 deposit-wallet order, is the funder contract).
opts: :timestamp (Unix seconds, default now) for the L2 signature.
Returns {:ok, %Polymarket.Schemas.SendOrderResponse{}} on success, or
{:error, %Polymarket.Schemas.ClobError{}} when the CLOB rejects the order (e.g.
an unfunded wallet's insufficient-balance error).
@spec post_orders( [Polymarket.Schemas.SendOrder.t()], Polymarket.Schemas.Credentials.t(), keyword() ) :: {:ok, [Polymarket.Schemas.SendOrderResponse.t()]} | {:error, Polymarket.Schemas.ClobError.t()}
Submits a batch of caller-constructed, already-signed orders to POST /orders.
The batch form of post_order/3: takes a list of Polymarket.Schemas.SendOrders
(each built and signed exactly as for post_order/3), serialises them into one
JSON array, authenticates the request with L2 HMAC headers from credentials, and
posts it. The CLOB processes the orders in parallel and caps a batch at 15; that
limit is enforced server-side (a 400 ClobError otherwise).
credentials must come from the auth functions (so its address — the api-key
owner EOA — is set for the POLY_ADDRESS header). opts: :timestamp (Unix
seconds, default now) for the L2 signature.
Returns {:ok, [%Polymarket.Schemas.SendOrderResponse{}]} — one entry per order,
in request order, each with its own success/status — or
{:error, %Polymarket.Schemas.ClobError{}} when the CLOB rejects the whole request
(e.g. an empty or over-15 batch, or an auth failure).