> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticated Sessions

> Set up authenticated access for Perps trading and account data

An authenticated session is a two-way authenticated communication channel with
the Perps system that allows your app to place orders, read private Perps account
data, and receive private real-time updates.

## Check Registration

Check whether an address already has a Perps account before setting up private
access. This lookup is public and does not create an account or credentials.

> [tab] TypeScript
>
> Use `fetchPerpsRegistration()` on a `PublicClient` or `SecureClient`. This example
> creates a public client and checks the account owner's address.
>
> ```ts theme={null}
> import { createPublicClient } from "@polymarket/client";
>
> const publicClient = createPublicClient();
> const registered = await publicClient.fetchPerpsRegistration({
>   address: "0x1111111111111111111111111111111111111111",
> });
> // registered: boolean
> ```

> [tab] Python
>
> Use `fetch_perps_registration()` on an `AsyncPublicClient` or `AsyncSecureClient`.
> This example creates a public client and checks the account owner's address.
>
> ```python theme={null}
> from polymarket import AsyncPublicClient
>
> async with AsyncPublicClient() as public_client:
>     registered = await public_client.fetch_perps_registration(
>         address="0x1111111111111111111111111111111111111111"
>     )
>     # registered: bool
> ```

> [tab] API
>
> Send the account owner's address to the public registration endpoint. No
> authentication headers are required.
>
> ```bash theme={null}
> curl --get "https://api.perpetuals.polymarket.com/v1/info/registered" \
>   --data-urlencode "address=0x1111111111111111111111111111111111111111"
> ```
>
> An example response for an address without a Perps account is:
>
> ```json theme={null}
> {
>   "registered": false
> }
> ```

A positive result means the address has a Perps account. Registration is
permanent. A negative result can be cached for up to ten seconds, so a newly
registered account may not appear immediately. Registration alone does not
confirm that credentials are valid or that the account has collateral available.

## Set Up Perps Access

> [tab] TypeScript
>
> **1. Create a Secure Client**
>
> Create a `SecureClient` for the Polymarket wallet that owns the Perps account,
> using the signer that controls it.
>
> ```ts theme={null}
> import { createSecureClient } from "@polymarket/client";
> import { privateKey } from "@polymarket/client/viem";
>
> const client = await createSecureClient({
>   wallet: process.env.POLYMARKET_WALLET_ADDRESS!,
>   signer: privateKey(process.env.PRIVATE_KEY!),
> });
> ```
>
> > [!NOTE]
> >
> > This example uses Viem for wallet signing. See the [TypeScript tooling
> > guide](https://docs.polymarket.com/getting-started/typescript.md#wallet-integrations) for other wallet
> > library integrations.
>
> **2. Open a Perps Session**
>
> Open a Perps session. By default, delegated Perps credentials expire after one
> week.
>
> ```ts theme={null}
> const session = await client.openPerpsSession();
> ```
>
> You can also set the session lifetime and label explicitly. `expiresIn` is
> measured in milliseconds.
>
> ```ts theme={null}
> const session = await client.openPerpsSession({
>   expiresIn: 7 * 24 * 60 * 60 * 1000,
>   label: "trading-app",
> });
> ```

> [tab] Python
>
> **1. Create a Secure Client**
>
> Create an `AsyncSecureClient` for the Polymarket wallet that owns the Perps
> account, using the signer that controls it.
>
> ```python theme={null}
> import os
>
> from polymarket import AsyncSecureClient
>
> client = await AsyncSecureClient.create(
>     private_key=os.environ["PRIVATE_KEY"],
>     wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
> )
> ```
>
> **2. Open a Perps Session**
>
> Open a Perps session. By default, delegated Perps credentials expire after one
> week.
>
> ```python theme={null}
> session = await client.open_perps_session()
> ```
>
> You can also set the session lifetime and label explicitly. `expires_in` is a
> `timedelta`.
>
> ```python theme={null}
> from datetime import timedelta
>
> session = await client.open_perps_session(
>     expires_in=timedelta(days=7),
>     label="trading-app",
> )
> ```

> [tab] API
>
> Start by registering new proxy credentials for an existing Polymarket account.
> If you do not have one yet, create an account at
> [polymarket.com](https://polymarket.com) first.
>
> **1. Generate a Proxy Signer**
>
> Generate a fresh keypair for the proxy signer. Perps uses this key to authorize
> trading operations on behalf of the Polymarket account signer, without requiring
> the account signer to sign every order.
>
> Use any secure EVM key-generation flow.
>
> ```bash Foundry theme={null}
> $ cast wallet new
> Successfully created new keypair.
> Address: <proxy_address>
> Private key: <proxy_private_key>
> ```
>
> ```ts Viem theme={null}
> import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
>
> const privateKey = generatePrivateKey();
> const { address } = privateKeyToAccount(privateKey);
> ```
>
> Store the private key securely. It will be used to sign Perps trading operations
> for the Polymarket account signer.
>
> **2. Create Proxy Typed Data**
>
> Create an EIP-712 `CreateProxy` payload.
>
> ```json theme={null}
> {
>   "domain": {
>     "name": "Polymarket",
>     "version": "1",
>     "chainId": 137
>   },
>   "primaryType": "CreateProxy",
>   "types": {
>     "CreateProxy": [
>       { "name": "addr", "type": "address" },
>       { "name": "exp", "type": "uint64" },
>       { "name": "salt", "type": "uint64" },
>       { "name": "ts", "type": "uint64" }
>     ]
>   },
>   "message": {
>     "addr": "<proxy_address>",
>     "exp": 1767225600000,
>     "salt": 123456789,
>     "ts": 1767000000000
>   }
> }
> ```
>
> Use these values consistently in the typed data and request body.
>
> | Field | Value |
> | - | - |
> | `addr` | `<proxy_address>` from the previous step. |
> | `exp` | Unix timestamp in milliseconds when the proxy signer stops being valid. |
> | `ts` | Current Unix timestamp in milliseconds. |
> | `salt` | Random integer generated for this signed request. |
>
> **3. Sign Proxy Typed Data**
>
> Sign the `CreateProxy` typed data with the signer for the Polymarket account.
>
> ```ts Viem theme={null}
> import { privateKeyToAccount } from "viem/accounts";
>
> const account = privateKeyToAccount("<polymarket_account_signer_private_key>");
>
> const signature = await account.signTypedData({
>   domain: {
>     name: "Polymarket",
>     version: "1",
>     chainId: 137,
>   },
>   primaryType: "CreateProxy",
>   types: {
>     CreateProxy: [
>       { name: "addr", type: "address" },
>       { name: "exp", type: "uint64" },
>       { name: "salt", type: "uint64" },
>       { name: "ts", type: "uint64" },
>     ],
>   },
>   message: {
>     addr: "<proxy_address>",
>     exp: 1767225600000,
>     salt: 123456789,
>     ts: 1767000000000,
>   },
> });
> ```
>
> **4. Authorize the Proxy Signer**
>
> Authorize the generated proxy signer for your Perps account.
>
> ```bash theme={null}
> curl -X POST "https://api.perpetuals.polymarket.com/v1/account/proxy" \
>   -H "content-type: application/json" \
>   -d '{
>     "op": {
>       "type": "createProxy",
>       "args": {
>         "owner": "<polymarket_account_signer_address>",
>         "proxy": "<proxy_address>",
>         "expiry": 1767225600000
>       }
>     },
>     "sig": "<signature>",
>     "salt": 123456789,
>     "ts": 1767000000000,
>     "label": "trading-app"
>   }'
> ```
>
> Map the request fields to the values from the previous steps.
>
> * `owner` is the signer address for the Polymarket account.
> * `proxy` is `<proxy_address>` from the first step.
> * `sig` is `<signature>` from the previous step.
> * `salt` and `ts` are the same values used in the typed data from step 2.
> * `label` is an identifier for this proxy credential instance.
>
> The response contains the proxy secret.
>
> ```json theme={null}
> {
>   "secret": "<proxy_secret>"
> }
> ```
>
> Store the proxy private key, proxy address, proxy secret, and expiry securely.

## Session Lifecycle

Open an authenticated session to start trading, read private Perps account data,
and receive private real-time updates.

> [tab] TypeScript
>
> **1. Listen for Session Events**
>
> After opening a Perps session, iterate over it to receive private real-time
> updates.
>
> ```ts theme={null}
> const session = await client.openPerpsSession();
>
> for await (const event of session) {
>   switch (event.type) {
>     case "order":
>       // Update local order state.
>       break;
>
>     case "fill":
>       // Update position, PnL, or execution history.
>       break;
>
>     case "portfolio":
>       // Refresh margin, equity, and position views.
>       break;
>   }
> }
> ```
>
> This example handles a few common session events. `order` and `fill` are the
> core trading updates, while `portfolio` provides periodic account-level snapshots
> for margin, equity, positions, and withdrawable balance.
>
> See [Reconcile Trade State](https://docs.polymarket.com/perps/trading.md#reconcile-trade-state) for how to use
> these events to keep local trading state in sync.
>
> **2. Close the Session**
>
> You can close the session at any time by calling `session.close()`. Closing a
> session releases local resources; stored credentials can still be resumed until
> they expire.
>
> ```ts theme={null}
> for await (const event of session) {
>   if (shouldCloseSession) {
>     await session.close();
>     break;
>   }
>
>   // …
> }
> ```

> [tab] Python
>
> **1. Listen for Session Events**
>
> After opening a Perps session, iterate over it to receive private real-time
> updates.
>
> ```python theme={null}
> session = await client.open_perps_session()
>
> async for event in session:
>     if event.type == "order":
>         # Update local order state.
>         pass
>     elif event.type == "fill":
>         # Update position, PnL, or execution history.
>         pass
>     elif event.type == "portfolio":
>         # Refresh margin, equity, and position views.
>         pass
> ```
>
> This example handles a few common session events. `order` and `fill` are the
> core trading updates, while `portfolio` provides periodic account-level snapshots
> for margin, equity, positions, and withdrawable balance.
>
> See [Reconcile Trade State](https://docs.polymarket.com/perps/trading.md#reconcile-trade-state) for how to use
> these events to keep local trading state in sync.
>
> **2. Close the Session**
>
> You can close the session at any time by calling `session.close()`. Closing a
> session releases local resources; stored credentials can still be resumed until
> they expire.
>
> ```python theme={null}
> async for event in session:
>     if should_close_session:
>         await session.close()
>         break
>
>     # …
> ```

> [tab] API
>
> **1. Authenticate a WebSocket Connection**
>
> Connect to the Perps WebSocket production URL.
>
> ```text theme={null}
> wss://ws.perpetuals.polymarket.com/v1/ws
> ```
>
> After the connection opens, send an authentication frame with the proxy address
> and proxy secret.
>
> ```json theme={null}
> {
>   "id": 1,
>   "req": "post",
>   "op": {
>     "type": "auth",
>     "args": {
>       "proxy": "<proxy_address>",
>       "secret": "<proxy_secret>"
>     }
>   }
> }
> ```
>
> Check the authentication response before subscribing to private channels.
>
> ```json Success theme={null}
> {
>   "id": 1,
>   "data": {
>     "status": "ok",
>     "pod": "gateway-ws-7b68c9d4f5-m2n8p"
>   }
> }
> ```
>
> ```json Failure theme={null}
> {
>   "id": 1,
>   "data": {
>     "status": "err",
>     "error": "<error_message>"
>   }
> }
> ```
>
> A successful acknowledgement includes `pod`, the identity of the gateway pod
> serving the connection. Record it with your connection logs so your activity
> can be matched against exchange logs. It is correlation metadata only — pods
> are not addressable, and a reconnect can land on a different pod. Treat the
> field as optional: older pods omit it during a rolling deploy, and failures
> never include it.
>
> **2. Handle Session Events**
>
> Authenticated WebSocket connections receive private session update frames. These
> examples show a few common events: `orders` and `fills` for trading activity,
> and `portfolio` for periodic account-level snapshots.
>
> ```json Order theme={null}
> {
>   "ch": "orders",
>   "ts": 1767225600000,
>   "ets": 1767225600000,
>   "sq": 1234567890,
>   "data": {
>     "oid": 1234567890,
>     "iid": 1,
>     "buy": true,
>     "p": "65000.00",
>     "qty": "0.01",
>     "tif": "gtc",
>     "po": false,
>     "status": "open",
>     "rest": "0.01",
>     "fill": "0",
>     "cts": 1767225600000,
>     "uts": 1767225600000
>   }
> }
> ```
>
> ```json Fill theme={null}
> {
>   "ch": "fills",
>   "ts": 1767225600000,
>   "ets": 1767225600000,
>   "sq": 1234567891,
>   "data": {
>     "tid": 987654321,
>     "oid": 1234567890,
>     "iid": 1,
>     "side": "long",
>     "p": "65000.00",
>     "qty": "0.01",
>     "taker": true,
>     "fee": "0.26",
>     "fea": "pUSD",
>     "psz": "0",
>     "pep": "0",
>     "pnl": "0",
>     "liq": false,
>     "adl": false,
>     "ts": 1767225600000
>   }
> }
> ```
>
> ```json Portfolio theme={null}
> {
>   "ch": "portfolio",
>   "ts": 1767225600000,
>   "ets": 1767225600000,
>   "sq": 1234567892,
>   "data": {
>     "positions": [],
>     "margin": {
>       "total_account_value": "10.00",
>       "available_order_margin": "10.00",
>       "total_initial_margin": "0",
>       "total_maintenance_margin": "0",
>       "total_position_value": "0"
>     },
>     "withdrawable": "10.00",
>     "in_liquidation": false,
>     "fee_tier": 0,
>     "timestamp": 1767225600000
>   }
> }
> ```
>
> These are examples of common session events, not the full event list.
> `ts` is the server send time. `ets` is the newest reflected event time, both in
> Unix milliseconds. An `ets` of `0` means the event horizon is unknown. Use `sq`
> for sequence-based reconciliation rather than treating send time as event order.
>
> **3. Keep the Connection Alive**
>
> Send an application-level ping from the client about every 25 seconds.
>
> ```json theme={null}
> {
>   "id": 0,
>   "req": "post",
>   "op": {
>     "type": "ping"
>   }
> }
> ```
>
> The server responds with a pong payload.
>
> ```json theme={null}
> {
>   "id": 0,
>   "data": {
>     "status": "ok",
>     "ts": 1767225600000,
>     "sq": 1234567890
>   }
> }
> ```
>
> Treat the connection as stale if no messages arrive for about 65 seconds.
>
> **4. Close the Connection**
>
> Close the WebSocket connection when the current workflow is finished. Closing the
> connection does not revoke the proxy credential.

## Resume a Session

Resume a session when stored credentials are still valid and a Perps workflow
needs to continue in a new runtime context.

> [tab] TypeScript
>
> Read `session.credentials` after opening a session and store the object in secure
> credential storage.
>
> ```ts theme={null}
> const credentials = session.credentials;
> // credentials: PerpsCredentials
> ```
>
> where `PerpsCredentials` is:
>
> ```ts PerpsCredentials Type theme={null}
> type PerpsCredentials = {
>   proxy: EvmAddress;
>   privateKey: PrivateKey;
>   secret: string;
>   expiresAt: number;
> };
> ```
>
> ```json PerpsCredentials Example theme={null}
> {
>   "proxy": "0x1111111111111111111111111111111111111111",
>   "privateKey": "0x2222222222222222222222222222222222222222222222222222222222222222",
>   "secret": "<proxy_secret>",
>   "expiresAt": 1766725200000
> }
> ```
>
> Pass stored credentials back to `openPerpsSession()` while they are still valid.
> The SDK validates them and resumes the session.
>
> ```ts theme={null}
> const session = await client.openPerpsSession({
>   credentials,
> });
> // session: PerpsSession
> ```

> [tab] Python
>
> Read `session.credentials` after opening a session and store the object in secure
> credential storage.
>
> ```python theme={null}
> credentials = session.credentials
> # credentials: PerpsCredentials
> ```
>
> where `PerpsCredentials` is:
>
> ```python PerpsCredentials Type theme={null}
> from polymarket import PerpsCredentials
>
> # credentials: PerpsCredentials
> ```
>
> ```json PerpsCredentials Example theme={null}
> {
>   "proxy": "0x1111111111111111111111111111111111111111",
>   "private_key": "0x2222222222222222222222222222222222222222222222222222222222222222",
>   "secret": "<proxy_secret>",
>   "expires_at": "2026-01-25T18:20:00Z"
> }
> ```
>
> For JSON-backed storage, serialize the model and keep the result encrypted.
>
> ```python theme={null}
> stored_credentials = credentials.model_dump(mode="json")
> ```
>
> Pass stored credentials back to `open_perps_session()` while they are still
> valid. The SDK validates them and resumes the session.
>
> ```python theme={null}
> from polymarket import PerpsCredentials
>
> credentials = PerpsCredentials.model_validate(stored_credentials)
>
> session = await client.open_perps_session(credentials=credentials)
> # session: PerpsSession
> ```

> [tab] API
>
> Resume an API session by reusing stored proxy credentials while they are still
> valid.
>
> Store the credential material from the setup flow in secure credential storage.
>
> | Field | Use it to |
> | - | - |
> | `<proxy_address>` | Identify the proxy credential. |
> | `<proxy_private_key>` | Sign Perps trading operations. |
> | `<proxy_secret>` | Authenticate private REST and real-time access. |
> | `expiry` | Know when to register a new proxy credential. |
>
> For private REST reads, pass the proxy address and proxy secret as headers.
>
> ```bash theme={null}
> curl "https://api.perpetuals.polymarket.com/v1/account/portfolio" \
>   -H "polymarket-proxy: <proxy_address>" \
>   -H "polymarket-secret: <proxy_secret>"
> ```
>
> For a new WebSocket connection, send the same authentication frame used when the
> session was opened.
>
> ```json theme={null}
> {
>   "id": 1,
>   "req": "post",
>   "op": {
>     "type": "auth",
>     "args": {
>       "proxy": "<proxy_address>",
>       "secret": "<proxy_secret>"
>     }
>   }
> }
> ```
>
> If the credential has expired, register a new proxy credential before resuming
> private workflows.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.