Get Position History
Retrieve closed position history for an authenticated subaccount with symbol and time-range filtering plus pagination.
Endpoint
POST https://papi.synthetix.io/v1/tradeRequest
Request Format
{
"params": {
"action": "getPositionHistory",
"subaccountId": "123456789",
"symbol": "BTC-USDT",
"startTime": 1769364177000,
"endTime": 1769450577000,
"limit": 50,
"offset": 0
},
"signature": {
"v": 27,
"r": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"s": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
params | object | Yes | Request parameters wrapper |
params.action | string | Yes | Must be "getPositionHistory" |
params.subaccountId | string | Yes | Subaccount ID in request payload. The authenticated selected account is enforced server-side for access control |
params.symbol | string | No | Filter by trading pair (for example "BTC-USDT") |
params.startTime | integer | No | Start timestamp in milliseconds (inclusive). Must not be older than 30 days in the past. When omitted, defaults to 30 days before the request time. Maximum range between startTime and endTime is 30 days |
params.endTime | integer | No | End timestamp in milliseconds (inclusive). When startTime is omitted, endTime must not fall before the 30-day lookback floor. Maximum range between startTime and endTime is 30 days |
params.limit | integer | No | Number of records to return (default: 100, max: 1000) |
params.offset | integer | No | Number of records to skip (default: 0, max: 10000) |
signature | object | Yes | EIP-712 signature for the request |
This read endpoint does not require nonce management in its request flow.
| Parameter | Type | Required | Description |
|---|---|---|---|
nonce | uint64 | Yes* | Positive integer nonce (must be incrementing and unique per request) |
signature | object | Yes | EIP-712 signature object |
expiresAfter | uint64 | No | Unix milliseconds expiration timestamp (5x rate limit on stale cancels) |
:::info Common Parameters
These are top-level request parameters. The subAccountId parameter is specified within the params object (see each endpoint's parameter table).
:::
:::info SubAccountAction Endpoints
Endpoints using SubAccountAction signing (getPositions, getOpenOrders, getOrderHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates, getWithdrawableAmounts) do not require the nonce parameter. Only signature and optional expiresAfter are needed.
:::
Response
Success Response
{
"status": "ok",
"response": {
"positions": [
{
"positionId": "2015847946616049664",
"symbol": "BTC-USDT",
"side": "long",
"entryPrice": "95000",
"quantity": "0.001",
"closePrice": "96000",
"closeReason": "close",
"leverage": 10,
"realizedPnl": "1",
"accumulatedFees": "0.1",
"netFunding": "0",
"closedAt": 1769450577774,
"createdAt": 1769450577000,
"tradeId": "123"
}
],
"hasMore": false
},
"requestId": "abcd1234",
"request_id": "abcd1234",
"timestamp": 1769450577774
}Response Fields
| Field | Type | Description |
|---|---|---|
status | string | "ok" on success, "error" on failure |
response | object | Container for result data |
response.positions | array | Closed position records for the requested filters |
response.hasMore | boolean | Whether additional records are available for pagination |
requestId | string | Request tracking identifier |
request_id | string | Legacy request tracking identifier (same value as requestId) |
timestamp | integer | Server timestamp in milliseconds |
Position History Object
| Field | Type | Description |
|---|---|---|
positionId | string | Unique position identifier |
symbol | string | Trading pair symbol |
side | string | Position side ("long" or "short") |
entryPrice | string | Average entry price |
quantity | string | Position size |
closePrice | string | Execution price of closure |
closeReason | string | Position close reason (for example "close") |
leverage | integer | Position leverage at the time of close. Omitted when not set |
realizedPnl | string | Realized PnL for this closed position |
accumulatedFees | string | Total fees paid for the position lifecycle |
netFunding | string | Net funding paid/received |
closedAt | integer | Position close timestamp in milliseconds |
createdAt | integer | Position creation timestamp in milliseconds |
tradeId | string | Associated trade identifier |
Error Response
{
"status": "error",
"error": {
"category": "REQUEST",
"message": "Invalid time range",
"code": "VALIDATION_ERROR",
"retryable": false
},
"requestId": "abcd1234",
"request_id": "abcd1234",
"timestamp": 1769450577774
}EIP-712 Signature
const domain = {
name: 'Synthetix',
version: '1',
chainId: 1,
verifyingContract: '0x0000000000000000000000000000000000000000'
};
const types = {
SubAccountAction: [
{ name: 'subAccountId', type: 'uint256' },
{ name: 'action', type: 'string' },
{ name: 'expiresAfter', type: 'uint256' }
]
};
const message = {
subAccountId: '123456789',
action: 'getPositionHistory',
expiresAfter: 0
};
const signature = await signer._signTypedData(domain, types, message);Signing
All trading methods are signed using EIP-712. Each successful trading request will contain:
- A piece of structured data that includes the sender address
- A signature of the hash of that structured data, signed by the sender
For detailed information on EIP-712 signing, see EIP-712 Signing.
Error Handling
| Error Code | Description | Retryable |
|---|---|---|
UNAUTHORIZED | EIP-712 signature validation failed | No |
VALIDATION_ERROR | Request validation failed | No |
MISSING_REQUIRED_FIELD | Required field is missing | No |
INVALID_FORMAT | Field format is invalid | No |
INVALID_VALUE | Invalid parameter value | No |
RATE_LIMIT_EXCEEDED | Too many requests in time window | Yes |
INSUFFICIENT_MARGIN | Not enough margin for trade | No |
ORDER_NOT_FOUND | Order does not exist | No |
OPERATION_TIMEOUT | Operation timed out | Yes |
| Error | Description |
|---|---|
| Invalid request format | Request payload is malformed |
| Invalid subaccount | Subaccount does not exist or is not accessible |
| Invalid time range | startTime is greater than endTime |
| Time range exceeds maximum | startTime and endTime are more than 30 days apart |
| startTime exceeds lookback | startTime is more than 30 days in the past |
| endTime before lookback floor | endTime falls before the 30-day lookback window when startTime is not provided |
| Offset exceeds maximum | offset is greater than 10000 |
| Invalid pagination | limit or offset is outside accepted bounds |
symbol is a filter field, but this endpoint does not document dedicated symbol-validation errors in its handler path.
