> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.
# Authentication
> How to authenticate requests to the CLOB API
The CLOB API uses two levels of authentication: **L1 (Private Key)** and **L2 (API Key)**. Either can be accomplished using the CLOB client or REST API.
## Public vs Authenticated
<CardGroup cols={1}>
<Card title="Public (No Auth)" icon="unlock">
The **Gamma API**, **Data API**, and CLOB read endpoints (orderbook, prices, spreads) require no authentication.
The CLOB uses two levels of authentication: L1 (Private Key) and L2 (API Key). Either can be accomplished using the CLOB client or REST API
### L1 Authentication
L1 authentication uses the wallet's private key to sign an EIP-712 message used in the request header. It proves ownership and control over the private key. The private key stays in control of the user and all trading activity remains non-custodial.
**Used for:**
* Creating API credentials
* Deriving existing API credentials
* Signing and creating user's orders locally
### L2 Authentication
L2 uses API credentials (apiKey, secret, passphrase) generated from L1 authentication. These are used solely to authenticate requests made to the CLOB API. Requests are signed using HMAC-SHA256.
**Used for:**
* Cancel or get user's open orders
* Check user's balances and allowances
* Post user's signed orders
<Info>
Even with L2 authentication headers, methods that create user orders still
require the user to sign the order payload.
</Info>
***
## Getting API Credentials
Before making authenticated requests, you need to obtain API credentials using L1 authentication.
### Using the SDK
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient } from "@polymarket/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
use polymarket_client_sdk_v2::auth::{LocalSigner, Signer};
use polymarket_client_sdk_v2::clob::{Client, Config};
let private_key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(POLYGON));
// Creates new credentials or derives existing ones,
// then initializes the authenticated client — all in one step
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let credentials = client.credentials();
println!("API Key: {}", credentials.key());
```
</Tab>
</Tabs>
<Warning>
**Never commit private keys to version control.** Always use environment
variables or secure key management systems.
</Warning>
### Using the REST API
While we highly recommend using our provided clients to handle signing and authentication, the following is for developers who choose NOT to use our [Python](https://github.com/Polymarket/py-clob-client-v2) or [TypeScript](https://github.com/Polymarket/clob-client-v2) clients.
**Create API Credentials**
```bash theme={null}
POST https://clob.polymarket.com/auth/api-key
```
**Derive API Credentials**
```bash theme={null}
GET https://clob.polymarket.com/auth/derive-api-key
```
Required L1 headers:
| Header | Description |
| ---------------- | ---------------------- |
| `POLY_ADDRESS` | Polygon signer address |
| `POLY_SIGNATURE` | CLOB EIP-712 signature |
| `POLY_TIMESTAMP` | Current UNIX timestamp |
| `POLY_NONCE` | Nonce (default: 0) |
The `POLY_SIGNATURE` is generated by signing the following EIP-712 struct:
<Accordion title="EIP-712 Signing Example">
<CodeGroup>
```typescript TypeScript theme={null}
const domain = {
name: "ClobAuthDomain",
version: "1",
chainId: chainId, // Polygon Chain ID 137
};
const types = {
ClobAuth: [
{ name: "address", type: "address" },
{ name: "timestamp", type: "string" },
{ name: "nonce", type: "uint256" },
{ name: "message", type: "string" },
],
};
const value = {
address: signingAddress, // The Signing address
timestamp: ts, // The CLOB API server timestamp
nonce: nonce, // The nonce used
message: "This message attests that I control the given wallet",
};
const sig = await signer._signTypedData(domain, types, value);
```
```python Python theme={null}
domain = {
"name": "ClobAuthDomain",
"version": "1",
"chainId": chainId, # Polygon Chain ID 137
}
types = {
"ClobAuth": [
{"name": "address", "type": "address"},
{"name": "timestamp", "type": "string"},
{"name": "nonce", "type": "uint256"},
{"name": "message", "type": "string"},
]
}
value = {
"address": signingAddress, # The signing address
"timestamp": ts, # The CLOB API server timestamp
"nonce": nonce, # The nonce used
"message": "This message attests that I control the given wallet",
}
sig = signer.sign_typed_data(domain, types, value)
| `POLY_PASSPHRASE` | User's API `passphrase` value |
The `POLY_SIGNATURE` for L2 is an HMAC-SHA256 signature created using the user's API credentials `secret` value. Reference implementations can be found in the [TypeScript](https://github.com/Polymarket/clob-client-v2/blob/main/src/signing/hmac.ts) and [Python](https://github.com/Polymarket/py-clob-client-v2/blob/main/py_clob_client_v2/signing/hmac.py) clients.
### CLOB Client
<Tabs>
<Tab title="TypeScript">
```typescript theme={null}
import { ClobClient, Side } from "@polymarket/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);