> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.6mm.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.6mm.com/_mcp/server.

# Perpetual Queries & Pagination

This guide targets **Agent Java SDK `v0.3.0`**, Java 8+, and the tagged public contract. Examples run in a partner backend after initializing `client` in [Quick Start](/sdk/agent-sdk/java/quick-start).

## Example prerequisites

The Java snippets share these imports. Initialize `client` using Quick Start and obtain `platformUserId` from the saved binding. Example user/order IDs must be replaced with your own persisted values.

```java
import com.sixmm.agent.*;
import com.sixmm.agent.model.*;
import java.util.*;
```

## Query perpetual contract data

### Six types of interfaces and Java methods

All requests are signed POST with a common prefix of `/v1/agent/perpetual`.

| path suffix          | Java Method/Request Type                                          | player range                                                       |
| -------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------ |
| `/orders/current`    | `listCurrentPerpetualOrders(CurrentPerpetualOrdersRequest)`       | NORMAL Player can be omitted; CONDITIONAL Player must be specified |
| `/orders/history`    | `listPerpetualOrderHistory(PerpetualOrderHistoryRequest)`         | Same as above                                                      |
| `/trades`            | `listPerpetualTrades(PerpetualTradesRequest)`                     | Player must be specified                                           |
| `/positions/current` | `listCurrentPerpetualPositions(CurrentPerpetualPositionsRequest)` | Players can be omitted                                             |
| `/positions/history` | `listPerpetualPositionHistory(PerpetualPositionHistoryRequest)`   | Players can be omitted                                             |
| `/account/ledger`    | `listPerpetualLedger(PerpetualLedgerRequest)`                     | Players can be omitted                                             |

`platformUserIds` is a string array of public platform IDs. When specified, 1 to 100 unique players who have access are required; on endpoints that allow omission, only the range of direct players that the current merchant has access to is queried. Trade-fill queries always require this array; conditional-order queries also require explicit user IDs. Omission is not equivalent to `[]`, and empty arrays are illegal. The scope is determined by the signing merchant, and other merchant IDs cannot be passed to expand the scope.

Array values are serialized as compact JSON before joining the signing payload. For example, `platformUserIds` signs as `["1188041528"]`, giving `platformUserIds=["1188041528"]` in the `k=v` payload. Preserve the array element order, double quotes and string IDs; do not insert formatting spaces or use Java `List.toString()` (such as `[1188041528]`). The SDK handles this serialization automatically.

The order query must pass `orderCategory=NORMAL` or `CONDITIONAL`. Use `orderId` for ordinary orders and `conditionId` for conditional orders. They cannot be mixed across categories. Conditional orders and the ordinary orders generated by triggering them are processed separately as entities.

### Filter conditions

| Query                | Available business filters                                                                                     |
| -------------------- | -------------------------------------------------------------------------------------------------------------- |
| Current order        | `orderCategory`, `symbol`                                                                                      |
| historical order     | `orderCategory`, `symbol`, `startTime`, `endTime`, `orderId`, `conditionId`, `clientOrderId`, `side`, `status` |
| make a deal          | `symbol`, `startTime`, `endTime`, `orderId`                                                                    |
| Current position     | `symbol`                                                                                                       |
| Historical positions | `symbol`, `startTime`, `endTime`, `positionSide`                                                               |
| Contract changes     | `startTime`, `endTime`, `assetType`, `changeType`                                                              |

The time of historical query is Unix **milliseconds**, and the interval is `[startTime, endTime)`; the time of requesting signature is `timestamp` is Unix **seconds**. It is recommended to fix the UTC time window and query in segments; use UTC for daily reconciliation. Status and type use platform contract enumeration and are not translated into Chinese strings by themselves.

`limit` Default is 500, range is 1\~1000; the page size does not guarantee that the same number will be returned every time. The six interfaces currently share a query quota of 2 times per second and 4 bursts per merchant, and the maximum concurrency limit for each merchant within the instance is 2. The merchant side uses a unified queue, and it is recommended to start with sequential paging and a smaller history window.

### Java query examples

Query a player's current ordinary order:

```java
CurrentPerpetualOrdersRequest current = new CurrentPerpetualOrdersRequest();
current.orderCategory = "NORMAL";
current.platformUserIds = Collections.singletonList(platformUserId);
current.symbol = "BTCUSDT";
current.limit = 100;
PerpetualResponse currentPage = client.listCurrentPerpetualOrders(current);
```

Query the contract changes in the last hour and process the cursor. The following example does not automatically retry; when the actual application encounters current limitation or temporary failure, follow the linked related guide to restore the same page.

```java
PerpetualLedgerRequest ledger = new PerpetualLedgerRequest();
ledger.platformUserIds = Collections.singletonList(platformUserId);
ledger.endTime = System.currentTimeMillis();
ledger.startTime = ledger.endTime - 3_600_000L;
ledger.limit = 100;
Set<String> seenCursors = new HashSet<>();

while (true) {
    PerpetualResponse page = client.listPerpetualLedger(ledger);
    for (PerpetualRecord row : page.data.items) {
        // Persist records idempotently by platformUserId, entityType and entityId.
    }
    if (!page.data.hasMore) {
        break;
    }
    String next = page.data.nextCursor;
    if (next == null || next.isEmpty() || !seenCursors.add(next)) {
        throw new IllegalStateException("游标未推进，停止查询并排查");
    }
    ledger.cursor = next;
    Thread.sleep(650L); // Other queries must share the same partner rate-limit queue.
}
```

### Return structure and saving rules

See [Common response and pagination](#common-response-and-pagination) for shared fields. Resource fields are documented in [Orders](/sdk/agent-sdk/java/perpetual-orders), [Trade fills](/sdk/agent-sdk/java/perpetual-trades), [Positions](/sdk/agent-sdk/java/perpetual-positions) and [Contract ledger](/sdk/agent-sdk/java/perpetual-ledger).

The six interfaces uniformly return `PerpetualResponse`:

```json
{
  "code": 0,
  "message": "success",
  "data": {
    "items": [],
    "nextCursor": "",
    "hasMore": false
  }
}
```

Each `items` contains `platformUserId`, `entityType`, `entityId`, `data`. Entity types include `ORDER`, `CONDITION_ORDER`, `TRADE_FILL`, `POSITION`, `ACCOUNT_LEDGER`. Use these three identity fields to build an idempotent key; do not treat the conditional order ID, order ID, and fill ID as the same number.

`data` Provides fields such as price, quantity, status, expense, profit and loss, or balance change by resource. Amount, price, quantity, and entity ID are handled as strings; business time is in milliseconds. Missing fields are not filled in to 0 and are not inferred from other entities.

The cursor is the paging position of a query, not a reliable incremental subscription, nor a guaranteed cross-page atomic snapshot. The current cursor is valid for 24 hours from the first round of generation; subsequent paging retains the same merchants, resources, player collections and filter conditions. The fixed window for historical pull is idempotent when pulled repeatedly; the status of the current order/position is refreshed after re-querying. When a real-time interface is needed, the data mechanism of the platform front-end is used, and the polling six interface cannot be regarded as a high-frequency market interface.

### Errors and recovery

HTTP success does not mean business success, you must check `code`. Java SDK will throw a business error as `AgentApiException`.

| Business code | Typical meaning                                                                               | Handling                                                                                                     |
| ------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `102001`      | Required parameters are missing, for example, the conditional order query is missing players. | Supply the missing parameters                                                                                |
| `102002`      | Illegal parameters, empty array, mismatched cursor or expired                                 | Correct the parameters; recheck the fixed window after clearing the expired cursor and save it idempotently. |
| `102003`      | Illegal limit, number of players, or time range                                               | Narrow or correct scope                                                                                      |
| `6001`        | Signature error                                                                               | Check key, array serialization and signature fields                                                          |
| `6009`        | Merchant access method or access scope is not allowed                                         | Check merchant permissions and player ownership                                                              |
| `6904`        | Service is temporarily unavailable, concurrency or query resource protection                  | Reduce concurrency and shrink windows; contact support if the error persists                                 |
| `6905`        | The shared quota for six types of queries has been exhausted                                  | Back off, then retry the original failed page                                                                |

The `cursor` and all filter conditions of the original failed page will be retained after current limiting, timeout or temporary failure; each time SDK is re-called, new `timestamp`, `nonce`, `sign` will be generated. You cannot jump directly to the next page, and you cannot treat failures as empty results. SDK is not responsible for automatically retrying fund transactions.

## Common response and pagination

| Field             | JSON type | illustrate                                                                                                                        |
| ----------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `code`            | integer   | Business code, 0 means success; if it is not 0, it will be treated as an error, and failure will not be treated as an empty page. |
| `message`         | string    | The description of the results is not the sole basis for business judgment.                                                       |
| `data`            | object    | Paginated results on success                                                                                                      |
| `data.items`      | array     | Records on this page; the legal empty page is `[]`                                                                                |
| `data.nextCursor` | string    | Next page cursor; usually an empty string if there are no subsequent pages                                                        |
| `data.hasMore`    | boolean   | Whether there are subsequent pages; when true, use nextCursor to continue the same query                                          |

The structure of each `data.items[]`:

| Field            | JSON type | illustrate                                                                                                                   |
| ---------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `platformUserId` | string    | Platform public user ID, saved as a string; not internal database user ID                                                    |
| `entityType`     | string    | The entity type to which the record belongs, see the table below                                                             |
| `entityId`       | string    | The identifier of the current entity is combined with the platform user and entity type to construct a local idempotent key. |
| `data`           | object    | The business fields of this entity; different resource fields are different                                                  |

| Query resources              | `entityType`      | `entityId` Correspondence                                                  |
| ---------------------------- | ----------------- | -------------------------------------------------------------------------- |
| Ordinary order               | `ORDER`           | `data.orderId`                                                             |
| conditional orders           | `CONDITION_ORDER` | `data.conditionId`                                                         |
| Trade fill details           | `TRADE_FILL`      | `data.fillId`, not tradeId                                                 |
| Current/historical positions | `POSITION`        | `data.positionId`                                                          |
| Contract ledger records      | `ACCOUNT_LEDGER`  | Single account change detail identification, \*\* is not data.ledgerId\*\* |

The same `ledgerId` can separate multiple details such as handling fees, profit and loss, etc.; pressing ledgerId to remove duplicates will cause data loss. IDs from different resources cannot be mixed. See the linked related guide of the Access Guide for paging and field saving rules.

## Types, units and omitted fields

* Amount, price, quantity, and entity ID use string; use decimal to process amounts, and cannot use floating point numbers or convert long IDs to JavaScript Numbers. The amount currency and quantity unit are explained according to the trading pair/contract specifications.
* Business time uses integer (int64), both are Unix milliseconds; request authentication timestamp and entry credentials expireAt use seconds and cannot be confused.
* String business fields are usually not output when they are empty, and some will be omitted when numeric fields are 0. **The missing field does not mean that the business value is 0**.
* `reduceOnly`, `closeOnly`, `makerOnly` in the general record model do not omit false, so these three false may also appear in transactions or positions. They are only explained in the order resources; it cannot be considered that the transaction/position executed the corresponding order rules.
* `closePosition` is an optional boolean: provided by conditional orders, usually omitted for other resources. Missing has a different meaning than false.
* The table below "currently provided" means that the read logic has a field source; optional fields may still be omitted because they have no value. The fields that exist in the model are not guaranteed to be filled in every interface.

## The difference between status and margin mode

| resource                                          | current return value                                                                                               |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Current ordinary order status                     | NEW, PENDING, PARTIALLY_FILLED                                                                                     |
| Historical ordinary order status                  | FILLED, CANCELED, REJECTED, PARTIAL_FILLED_CANCELED, or PARTIALLY_FILLED_CANCELED; keep the actual source spelling |
| Current condition order status / triggerStatus    | PENDING_ACTIVATION, PENDING, TRIGGERING                                                                            |
| Historical condition order status / triggerStatus | TRIGGERED, CANCELLED, REJECTED, FIRED                                                                              |
| Current position status                           | Numeric string "1" is in position, "3" is in liquidation                                                           |
| Historical position status                        | Numeric string "2" has closed the position, "4" has forced liquidation                                             |

The spelling of CANCELED for an ordinary order is different from that of CANCELLED for a conditional order; triggering of a conditional order does not mean that the generated ordinary order has been filled. Do not reuse the same set of status translation tables for all resources.

Conditional order marginMode returns CROSS / ISOLATED; historical ordinary orders and positions currently return "1" / "2", which are cross/isolated margin respectively. marginMode is currently not available for ordinary orders. Merchants can normalize by resource in their own display layer, and the original values ​​still need to be saved.

## Fields declared in the model but not provided in this query

Generic RecordData / Java The PerpetualData model also declares the following fields, but the current six-category production read logic does not populate them. \*\*Should not be listed as available business data, nor should field defaults be substituted for real results. \*\*

| Field            | Model type | current boundary                                                                                                              |
| ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `closeReason`    | string     | Reasons for closing historical positions are not provided                                                                     |
| `walletDelta`    | string     | The account change interface does not return wallet delta                                                                     |
| `frozenDelta`    | string     | The account change interface does not return frozen delta                                                                     |
| `usedDelta`      | string     | The account change interface does not return the used margin delta                                                            |
| `feeDelta`       | string     | The account change interface does not return the fee delta                                                                    |
| `pnlDelta`       | string     | The account change interface does not return profit and loss delta                                                            |
| `accountVersion` | string     | The account change interface does not return the account version and cannot be used for reliable incremental synchronization. |
| `occurredAt`     | integer    | The account change interface uses createdAt and does not provide another set of event occurrence times.                       |

The actual field application scope is subject to the above resource tables; when the platform updates fields or enumerations, it shall be adapted according to the new interface description and SDK version.

## Source and related guides

* [Official v0.3.0 source](https://github.com/6mm-com/agent-java-sdk/tree/54aa3c1)
* [Funding wallet](/sdk/agent-sdk/java/funding-wallet)
* [Upgrade guide](/sdk/agent-sdk/java/upgrade)