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). Maximum range between startTime and endTime is 30 days |
params.endTime | integer | No | End timestamp in milliseconds (inclusive). 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, getOrdersHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates) 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",
"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") |
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 |
| 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.