Trade Accounts
Connect and manage the exchange accounts Pear trades on your behalf.
A trade account links your Pear identity to one connected exchange account on Hyperliquid, Binance, Bybit, OKX, or Lighter. You connect an account once, then scope every trading call to it with the x-trade-account-id header.
Exchange credentials are stored encrypted. One endpoint returns them decrypted to the account's owner, POST /trade-accounts/{id}/credentials, which is how a client talks to the venue directly.
Manage trade accounts
| Endpoint | Purpose |
|---|---|
GET /trade-accounts | List your connected accounts. |
POST /trade-accounts | Connect an exchange account. Returns 201 with { "account": … }. |
PATCH /trade-accounts/{id} | Change the alias, the credentials, or the metadata. |
POST /trade-accounts/{id}/credentials | Read the account's decrypted venue credentials. |
DELETE /trade-accounts/{id} | Soft-delete an account. Returns 204. |
POST /trade-accounts/{id}/restore | Restore a soft-deleted account. Returns 204. |
List your accounts
curl "https://pro-gateway.pearprotocol.io/trade-accounts" \
-H "x-api-key: $PEAR_API_KEY"{
"accounts": [
{
"id": "9c1b2d3e-4f56-4789-a0b1-c2d3e4f56789",
"alias": "main",
"connector": "hyperliquid",
"exchangeIdentifier": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984",
"metadata": {
"agentWalletAddress": "0xa1b2c3d4e5f60718293a4b5c6d7e8f9012345678",
"isSubaccount": false,
"mainAccountAddress": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"
},
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
}
]
}Hyperliquid always reports all three metadata keys, and Lighter always reports l1_address. Binance, Bybit, and OKX carry no metadata at all, so the key is absent.
Pass the id as x-trade-account-id on every account-scoped request. Add ?includeDeleted=true to see soft-deleted accounts before you restore one; those rows also carry deletedAt.
Connect an account
Connecting takes that venue's credentials. On Hyperliquid:
{
"connector": "hyperliquid",
"alias": "main",
"exchangeIdentifier": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984",
"credentials": { "signer_key": "0x…" },
"metadata": {
"agentWalletAddress": "0xa1b2c3d4e5f60718293a4b5c6d7e8f9012345678",
"isSubaccount": false,
"mainAccountAddress": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"
}
}Creation calls the venue before it stores anything. The gateway validates the credentials against the live exchange and resolves the exchange account they control. Any refusal by the venue comes back as a 400 carrying the venue's own wording. See Connect an Exchange for what each venue checks.
Connecting the same exchange account twice is also a 400: Exchange account already linked to another trade account. If the existing row is soft-deleted, the message asks you to restore it instead, which is what POST /trade-accounts/{id}/restore is for.
Credentials per venue
| Exchange | credentials | Also required |
|---|---|---|
| Hyperliquid | signer_key | exchangeIdentifier (the wallet address), and metadata with agentWalletAddress, isSubaccount, mainAccountAddress. |
| Binance | read and write key pairs | — |
| Bybit | api_key, api_secret | — |
| OKX | api_key, api_secret, api_pass | — |
| Lighter | api_private_key, api_key_index (4–254) | exchangeIdentifier (the account index, digits only), and metadata.l1_address. |
Every venue takes an alias, 1 to 100 characters, which is the label you see in listings.
exchangeIdentifier is a request field on Hyperliquid and Lighter only. Binance, Bybit, and OKX do not accept one: the gateway reads the account id back from the venue (the Binance uid, the Bybit userID, the OKX uid) and stores that.
This endpoint does not set up the venue. Hyperliquid and Lighter both need a funded account and on-chain approvals before the credentials work, and those steps happen against the exchange. Binance, Bybit, and OKX need only an API key. See Connect an Exchange for the per-venue walkthrough, including the builder and integrator approvals and the 6 bps minimum both require.
Update an account
PATCH /trade-accounts/{id} takes a body keyed by connector:
{
"connector": "hyperliquid",
"alias": "main-agent",
"credentials": { "signer_key": "0x…" },
"metadata": {
"agentWalletAddress": "0xa1b2c3d4e5f60718293a4b5c6d7e8f9012345678",
"isSubaccount": false,
"mainAccountAddress": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"
}
}| Field | Rule |
|---|---|
connector | Required on every PATCH. It selects which venue's shape the rest of the body is read as. It must equal the stored connector, or the call returns 403 Cannot change connector type. |
alias | Optional. 1 to 100 characters. |
credentials | Optional, and complete for that venue when sent. New credentials are validated against the exchange. |
metadata | Optional, and not partial: send every key the venue defines. Binance, Bybit, and OKX accept no metadata. |
exchangeIdentifier is not patchable. A body with nothing but connector returns 400 No data to update or 400 No changes detected.
Two Hyperliquid rules follow from the venue call:
- Changing
metadatawithout sendingcredentialsreturns400 Private key is required to update Hyperliquid wallet metadata. The private key is the proof that you control the agent wallet you are naming. - Credentials that resolve to a different exchange account return
400 Cannot change exchange account. Delete this trade account and create a new one.
Read the stored credentials
POST /trade-accounts/{id}/credentials returns the account's venue credentials in plaintext, so a client can call the exchange itself. It is a POST, not a GET, so that the write-scope rule applies to it: a read-only API key and a read-only OAuth grant are both refused. See Authentication.
{
"connector": "hyperliquid",
"account": {
"id": "9c1b2d3e-4f56-4789-a0b1-c2d3e4f56789",
"alias": "main",
"connector": "hyperliquid",
"exchangeIdentifier": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984",
"metadata": {
"agentWalletAddress": "0xa1b2c3d4e5f60718293a4b5c6d7e8f9012345678",
"isSubaccount": false,
"mainAccountAddress": "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"
},
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
},
"credentials": { "signer_key": "0x…" }
}credentials carries the same field names the connect call took: signer_key for Hyperliquid, read and write pairs for Binance, api_key/api_secret for Bybit, plus api_pass for OKX, and api_private_key/api_key_index for Lighter.
The TypeScript exchanges SDK is built on this endpoint: exchanges.connect(tradeAccountId) calls it and hands the result to status(), createTracker(), and the rest. See Venue Accounts.
Scoping requests
Send the account id on each trading call or account read:
x-trade-account-id: 9c1b2d3e-4f56-4789-a0b1-c2d3e4f56789There is no default. One connected account is treated the same as ten: an account-scoped route with no header returns 400 Missing required header: X-Trade-Account-Id.
| Status | When |
|---|---|
400 | The header is missing on an account-scoped route. |
400 | The header value is not a UUID. |
404 | No such trade account, or the account belongs to another user. The two cases are deliberately indistinguishable. |
The same 404 applies to PATCH, DELETE, restore, and credentials when the id in the path is not yours.