Skip to main content
Every request is signed with your partner API key. Polymarket identifies your platform from the key and never from the request body, so a request can only read and create your own trades. The API key identifies your platform. It does not authorize moving funds: each counterparty authorizes its own side through its order signature.

Your API Key

Polymarket issues each partner an API key during onboarding:
  • Key ID: the public half, sent on every request.
  • Secret: a base64url-encoded string, shared once through a secure channel. Decode it to bytes before using it as the HMAC key.

Sign a Request

Sign every request except GET /v1/time:
1

Create the Request Timestamp

First, create a new Unix timestamp in seconds for each request. It must be within 30 seconds of server time, in either direction. See Keep Your Clock in Sync.
2

Create the Request Signature

Next, concatenate the timestamp, the uppercase HTTP method, the request path, and the exact serialized body you send, with no separators. Then sign the result with your API key’s secret, decoded from base64url:
Where:
  • request_path is the URL path only. The query string is not signed.
  • body is the exact bytes sent. For a GET, it is empty. Serialize the body once and reuse that string for both the signature and the request, to avoid mismatches from key ordering or whitespace.
  • rfq_signature is base64url-encoded with padding (RFC 4648 §5). It is not hex and not standard base64.
These helpers create the three headers for a request:
Use these inputs to check your implementation:
3

Send an Authenticated Request

Finally, send the key ID, the timestamp, and the signature as headers. This request validates the terms of a trade:
Every authenticated request uses the same three headers:

Keep Your Clock in Sync

RFQ-Timestamp must be within 30 seconds of server time, in either direction. Keep your clock NTP-synced. If your requests start failing with 401, compare your clock with the server’s: GET /v1/time needs no authentication.
The response body gives the server time:
timestamp is the server time in Unix seconds, in the same format as RFQ-Timestamp.

Authenticate the WebSocket

The trade status stream is authenticated once, on the upgrade request. Sign it like any GET, with an empty body, and send the same three headers on the handshake:
The stream then delivers only your own trades. See Track the Trade.

Authentication Errors

A request that fails authentication returns 401 with code authentication_failed. Missing headers, a timestamp that isn’t whole Unix seconds, and a timestamp outside the 30-second window each have their own message. An unknown or revoked key ID and a signature mismatch share one generic message, for security.