Client ID
Attribute the trades your integration routes, then read back your own volume, open interest, users, and leaderboard with the same code.
A client ID is a short code that Pear issues to your integration. Send it on every trading call. Pear records it on the orders, executions, and fills that result, and you read your own numbers back with the same code.
It does three jobs:
| Job | How it works |
|---|---|
| Volume tracking for partners | Every trade your integration routes is attributed to your code, so Pear can measure the volume you bring. |
| Your own metrics | The statistics endpoints take your code and return only your slice: volume, fees, open interest, users, and a leaderboard of your traders. |
| Fee routing | Pear can price a client ID with its own fee rate and discounts, separate from the base rate. |
To get a code, contact Pear.
A client ID is not a credential
The code is a label. It does not sign in, authorize anything, or select an account. The gateway checks only that the code exists and is active. Three separate values ride on a trading call, and each answers a different question:
| Value | Question it answers |
|---|---|
x-api-key or Authorization: Bearer | Who is the user? See Authentication. |
x-trade-account-id | Which connected exchange account trades? See Trade Accounts. |
clientId | Which integration routed the trade? |
Your client ID is also none of these: the OAuth client_id, the API key UUID, the raw API key, the user ID, or the trade-account ID. It is a code of its own, 1 to 64 characters, matched exactly and case-sensitively, such as pear-web.
Send the exact string. The clientId body field is not trimmed, so a stray space makes the code unknown and the trading call fails.
Send it on a trade
clientId is an optional body field on every endpoint that places or schedules an order:
| Action | Endpoint |
|---|---|
| Open a basket | POST /trade/open |
| Adjust a position | POST /trade/{positionId}/adjust |
| Close a position | POST /trade/{positionId}/close |
| Reverse a position | POST /trade/{positionId}/reverse |
| Close every position | POST /trade/close-all |
| Open on a condition | POST /triggers/open |
| Close on a condition | POST /triggers/close |
| Schedule a TWAP | POST /schedules |
| Create a ladder | POST /ladders |
| Rebalance manually | POST /rebalance/manual/{positionId} |
curl -X POST "https://pro-gateway.pearprotocol.io/trade/open" \
-H "x-api-key: $PEAR_API_KEY" \
-H "x-trade-account-id: $TRADE_ACCOUNT_ID" \
-H "Content-Type: application/json" \
-d '{
"type": "MARKET",
"legs": [
{ "symbol": "0", "side": "BUY", "mode": "USD", "amount": "500" },
{ "symbol": "1", "side": "SELL", "mode": "USD", "amount": "500" }
],
"clientId": "your-client-id"
}'Three rules:
- Send it on every call. The gateway remembers nothing between requests.
- Omit it and the trade is unattributed. The trade still runs. It counts in the protocol totals and lands in the
otherbucket, not in yours. - An unknown or inactive code fails the call with
400. Nothing is placed. See Error Handling.
With the SDK
Set the code once in the SDK config. @pear-protocol/core-sdk then adds it to the body of trade, trigger, schedule, and manual-rebalance calls:
const sdk = new PearSDK({
// ...auth and trade-account config
clientId: 'your-client-id',
});A clientId you pass in a call body wins over the configured one. Two calls are not filled in for you, trade.reverse and ladders.create, so set clientId in the body yourself there.
From an agent
The Orchard MCP takes the same code on its own surface, as a request header rather than a body field:
x-client-id: <client-code>That header is the MCP's, not the gateway's. The gateway itself reads only the clientId body field; the MCP translates. See the Pear MCP integration guide for which tools it covers.
Where the code is recorded
Pear stores your client ID on the order, on the execution that ran it, on the trigger, ladder, or schedule that created it, and on every resulting fill.
Positions hold no client ID of their own. A position belongs to the client of its opening fill, and to exactly one. Attribution is therefore never split between two integrations, and your scoped numbers are always a subset of the protocol totals, never larger.
The public WebSocket trade.executed event also carries clientId. See WebSocket.
Read your own metrics
Four endpoints take clientId as a query parameter and return only what your code routed. They are public, so they need no API key and no trade account. Statistics is the full reference for all four; this is the short version.
| Endpoint | Returns |
|---|---|
GET /statistics/volume | Volume, fees, trade count, users, and new users per time bucket. |
GET /statistics/oi | Open interest per time bucket. |
GET /statistics/totals | All-time volume, fees, trades, and users. |
GET /statistics/leaderboard | Your traders, ranked by net PnL, volume, trade count, or average position ROI. |
curl "https://pro-gateway.pearprotocol.io/statistics/volume?connector=hyperliquid&resolution=24h&clientId=your-client-id"{
"data": [
{ "timestamp": 1767225600000, "volume": 4820000, "fees": 2892, "trades": 314, "users": 87, "newUsers": 12 }
]
}The four do not take the same parameters:
| Parameter | Rule |
|---|---|
connector | Required on volume, OI, and totals. Optional on the leaderboard, where absent means every venue. |
resolution | Required on volume and OI. 1h, 4h, or 24h. Not taken by totals. |
startDate, endDate | Optional on volume, OI, and the leaderboard. Not taken by totals, which are all-time. startDate must be before endDate or the call fails with 400. The format differs: ISO 8601 on volume and OI, Unix seconds on the leaderboard. |
clientId | Optional. Absent serves the protocol-wide numbers. |
How to read the numbers:
newUsersis new to you. It counts a user's first ever fill through your integration on that connector. A trader who already traded on Pear elsewhere still counts as new the first time they trade through you.clientId=otheris the unattributed bucket, every trade that carried no code at all. It works on volume, OI, and totals. On the leaderboard it returns an empty array, becauseotheris not a real code and the board resolves the code before it ranks anything.- Omit
clientIdand you get the protocol-wide series instead. - An unknown code returns an empty series or zero totals, not an error. Read calls do not fail on a bad code; trading calls do.
- The scoped leaderboard ranks trade accounts, not integrations. It scores only the positions whose opening fill carried your code, so it is the board of your own traders.
- The leaderboard hides traders who never linked an X account.
includeUnlinkedXdefaults tofalse, and the gate runs before the top-N cut, so an unlinked trader does not take a slot and then get dropped. PassincludeUnlinkedX=trueto rank everyone. - The
clientIdquery parameter is trimmed on volume, OI, and totals, and not on the leaderboard. A stray space is forgiven on the first three and returns an empty board on the fourth.
Fees
A client ID is a pricing dimension, so Pear can quote your integration differently from the base rate:
- An override scoped to your client ID replaces the base fee on every trade that carries the code. It can sit below or above base. Where a client-ID override and a user override both apply, the client-ID one wins.
- Discounts scoped to your client ID come off after the override. Discounts add up rather than compound, and a discount can cap how many executions each user may redeem it on.
Quote what a trade would pay before you send it, on the same attribution route. Unlike the four statistics endpoints, GET /fee is not public: it needs an API key and a trade account, and it takes the connector from that account rather than from a query parameter.
curl "https://pro-gateway.pearprotocol.io/fee?clientId=your-client-id" \
-H "x-api-key: $PEAR_API_KEY" \
-H "x-trade-account-id: $TRADE_ACCOUNT_ID"{
"feeRecipient": "0x…",
"baseBps": "3.5",
"overrideBps": "2.5",
"overrideScope": "client_id",
"discounts": [{ "scope": "client_id", "rate": "0.2" }],
"finalBps": "2.0"
}finalBps is what the trade pays. Quoting never spends a capped discount. See GET /fee and Trading Fees.
Get a client ID
Contact Pear with the name of your integration and where it trades. Pear creates the code, activates it, and tells you the exact string to send.
The code is fixed once created; the label beside it is not. Pear can deactivate a code, after which trading calls that carry it fail with 400.
Next: Executing Trade for the calls that carry the code.