Java SDK for the 6MM Agent REST API.
This SDK is intended for partner backend services. It wraps request signing, timestamp and nonce generation, amount formatting, HTTP calls, business exceptions, FX reference-rate queries, entry URL creation, Trading Widget embed token creation, Funding wallet transfers, execution-environment selection, six perpetual-data queries, and webhook signature verification.
Chinese documentation: README.zh-CN.md
Partner guides: seconds trading, wallets, simulated trading and SDK upgrades (Chinese) · perpetual response fields (Chinese).
- Java 8+
- Maven 3.9+
| Category | Scenario | SDK API | Description |
|---|---|---|---|
| User binding | Bind user | bind |
Create or fetch the binding between a partner user and a 6MM platform user |
| Asset queries | Query partner account | queryAccount |
Query the partner margin or funding account |
| Asset queries | Query user assets | queryUserAssets |
Query Contract assets; use withFunding() to include Funding balances |
| Transfers | Fixed amount transfer | transfer |
Transfer funds into or out of 6MM |
| Transfers | Transfer all out | transferAllOut |
Move all withdrawable user balance back to the partner platform |
| Transfers | Reverse order | reverse |
Reverse a successful transfer when the backend supports a compensation flow |
| Transfers | Query order | queryOrder |
Query one transfer order by partner order number |
| Transfers | List orders | listOrders |
Page through transfer orders for reconciliation |
| Transfers | Webhook verification | WebhookVerifier.verify |
Verify transfer final-state callbacks from 6MM |
| Funding wallet | Funding transfer | walletTransfer |
Partner ↔ Funding or Funding ↔ Contract; confirm the returned status |
| Funding wallet | Funding transfer status | queryWalletTransfer |
Recover a Funding operation using its original partner order number |
| Trading entry | Direct entry URL | createEntryUrl |
Create a one-time SSO URL for redirect mode |
| Trading entry | Embed token | createEmbedToken |
Create a short-lived token for Trading Widget tokenProvider mode |
| Perpetual data | Current perpetual orders | listCurrentPerpetualOrders |
Query current NORMAL or CONDITIONAL orders |
| Perpetual data | Perpetual order history | listPerpetualOrderHistory |
Query terminal NORMAL or CONDITIONAL orders |
| Perpetual data | Perpetual trades | listPerpetualTrades |
Query trade fills for an explicit public player list |
| Perpetual data | Current perpetual positions | listCurrentPerpetualPositions |
Query current positions |
| Perpetual data | Perpetual position history | listPerpetualPositionHistory |
Query closed positions |
| Perpetual data | Perpetual account ledger | listPerpetualLedger |
Query individual Contract balance-change records |
| Fiat reference rates | List supported fiat currencies | listSupportedFiatCurrencies |
List fiat currencies currently convertible to USDT |
| Fiat reference rates | Query FX reference rates | queryExchangeRates |
Query daily fiat-to-USDT reference ratios for all or selected currencies |
| Service information | Service version | version |
Query Agent service version information |
Obtain the following values from 6MM before integrating.
| Item | Example | Description |
|---|---|---|
baseUrl |
https://agent-api.6mm.com |
Agent API base URL, without a trailing slash |
agentCode |
AGENT001 |
Partner code |
apiSecret |
your-api-secret |
API signing secret. Keep it on the backend only |
defaultCurrency |
USDT |
Default currency, usually USDT |
webhookUrl |
https://partner.example.com/6mm/webhook |
Partner endpoint for 6MM callbacks |
Production recommendations:
- Use HTTPS for Agent API and webhook endpoints.
- Store
apiSecretin a secret manager, configuration center, or environment variable. - Keep server time synchronized, preferably with NTP.
- Persist all partner order numbers and keep them globally unique.
- Never send
apiSecretto browsers, apps, mini programs, or frontend source code.
Current source coordinates:
<dependency>
<groupId>com.sixmm.exchange.sdk</groupId>
<artifactId>agent</artifactId>
<version>0.3.0</version>
</dependency>GitHub is source hosting, not a Maven dependency repository. If the SDK has not been published to a Maven repository yet, install it into your local Maven repository first:
git clone https://github.com/6mm-com/agent-java-sdk.git
cd agent-java-sdk
git checkout v0.3.0
mvn installAfter local installation, your business project can resolve
com.sixmm.exchange.sdk:agent:0.3.0 from the local Maven repository.
For team builds and test environments, publish the SDK to a Maven repository such as Nexus, Artifactory, GitHub Packages, Maven Central, or use a GitHub based build service such as JitPack.
For an existing integration, see the SDK upgrade guide. Use the stable v0.3.0 source tag to install the SDK and read its matching integration documentation.
Funding wallets support USDT through walletTransfer. The directions are
PARTNER_TO_FUNDING, FUNDING_TO_PARTNER, FUNDING_TO_CONTRACT, and
CONTRACT_TO_FUNDING. Only Funding ↔ Contract supports transferAll=true;
otherwise pass a positive decimal amount string.
import com.sixmm.agent.model.ExecutionEnvironment;
import com.sixmm.agent.model.QueryUserAssetsRequest;
import com.sixmm.agent.model.QueryUserAssetsResponse;
import com.sixmm.agent.model.WalletTransferRequest;
import com.sixmm.agent.model.WalletTransferQueryRequest;
import com.sixmm.agent.model.WalletTransferResponse;
QueryUserAssetsResponse assets = client.queryUserAssets(
QueryUserAssetsRequest.of("1188041528")
.withFunding()
.withEnvironment(ExecutionEnvironment.SIMULATED));
WalletTransferResponse transfer = client.walletTransfer(
WalletTransferRequest.of("SIM-FUNDING-UNIQUE-001", "agent-user-001",
"PARTNER_TO_FUNDING", "10.00000000", false)
.withEnvironment(ExecutionEnvironment.SIMULATED));
// 结果未知或 PROCESSING 时查询原单,不换单号重新划转。
WalletTransferResponse status = client.queryWalletTransfer(
WalletTransferQueryRequest.of("SIM-FUNDING-UNIQUE-001")
.withEnvironment(ExecutionEnvironment.SIMULATED));Funding uses /v1/agent/wallet-transfer and /v1/agent/wallet-transfer-status.
Check status (SUCCESS, PROCESSING, FAILED), not the legacy transfer
orderStatus. Preserve the original order number and environment when recovering
an unknown result; legacy queryOrder is not the Funding status API.
Supported wallet/transfer request models expose withEnvironment: omitted or
PRODUCTION selects real funds; SIMULATED selects simulated funds. Set the
frontend trading mode and HTTP/WS targets separately. User binding and generic
entry authentication do not select the funds environment. The six perpetual
queries currently query production data and do not accept environment.
Seconds trading uses Funding balances and the same createEntryUrl /
createEmbedToken authentication as perpetual trading. Configure the seconds
page through the frontend; issuing or refreshing a token does not move funds.
See the partner integration guide for the complete flow.
import com.sixmm.agent.AgentClient;
import com.sixmm.agent.AgentClientConfig;
AgentClient client = new AgentClient(AgentClientConfig.builder()
.baseUrl("https://agent-api.6mm.com")
.agentCode("AGENT001")
.apiSecret("your-api-secret")
.defaultCurrency("USDT")
.build());import com.sixmm.agent.AgentClient;
import com.sixmm.agent.AgentClientConfig;
import java.time.Duration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AgentSdkConfig {
@Bean
public AgentClient agentClient(AgentSdkProperties props) {
return new AgentClient(AgentClientConfig.builder()
.baseUrl(props.getBaseUrl())
.agentCode(props.getAgentCode())
.apiSecret(props.getApiSecret())
.defaultCurrency("USDT")
.timeout(Duration.ofSeconds(10))
.build());
}
}Example application properties:
agent.sdk.base-url=https://agent-api.6mm.com
agent.sdk.agent-code=AGENT001
agent.sdk.api-secret=${AGENT_API_SECRET}For signed Agent API calls, the SDK automatically injects:
| Field | Source | Description |
|---|---|---|
agentCode |
AgentClientConfig.agentCode |
Partner code |
timestamp |
Current UTC Unix timestamp | Seconds |
nonce |
Secure random generator | Replay protection |
sign |
HMAC-SHA256 | Request signature |
currency |
defaultCurrency |
Filled when transfer/account requests omit currency |
Signing rules:
- Exclude
sign. - Exclude empty values.
- Sort keys by ASCII order.
- Join as
k=v&k2=v2. - Calculate HMAC-SHA256 hex with
apiSecret.
Normal business code should not calculate signatures or manually set
agentCode, timestamp, nonce, or sign.
Both FX methods use the normal signed Agent API flow. Start by discovering the currently supported source currencies:
import com.sixmm.agent.model.ListSupportedFiatCurrenciesResponse;
ListSupportedFiatCurrenciesResponse supported = client.listSupportedFiatCurrencies();
System.out.println(supported.targetCurrency); // USDT
System.out.println(supported.sourceCurrencies); // AUD, BRL, CNY, EUR, USD, ...Query all supported fiat-to-USDT reference rates:
import com.sixmm.agent.model.ExchangeRateItem;
import com.sixmm.agent.model.QueryExchangeRatesResponse;
QueryExchangeRatesResponse rates = client.queryExchangeRates();
for (ExchangeRateItem item : rates.rates) {
System.out.println("1 " + item.sourceCurrency + " = " + item.rate + " " + item.targetCurrency);
}Query selected currencies:
import com.sixmm.agent.model.QueryExchangeRatesRequest;
QueryExchangeRatesResponse rates = client.queryExchangeRates(
QueryExchangeRatesRequest.of("CNY", "EUR", "USD"));The request factory trims and uppercases currency codes and serializes them as
the comma-separated sourceCurrencies value required by the API. Omitting the
request or all effective currency values queries every supported currency.
| Response field | Type | Description |
|---|---|---|
snapshotVersion |
string | Stable snapshot version for audit and reconciliation |
provider |
string | Upstream provider, currently ECB |
sourceDate |
string | Upstream observation date in yyyy-MM-dd format |
fetchedAt / expiresAt |
int64 | Unix timestamps in milliseconds |
pricingPolicy |
string | Currently FIXED_PEG |
usdtUsdRate |
string | USD amount per 1 USDT, currently fixed at 1 |
rateType |
string | Currently INDICATIVE_DAILY |
usage |
string | Currently REFERENCE_ONLY |
rateMeaning |
string | 1 sourceCurrency = rate USDT |
rates[].rate |
string | USDT amount corresponding to one unit of source fiat |
These values are references for a partner multi-currency wallet to calculate
the USDT amount sent to 6MM. They are not executable prices, locked quotes, or
real-time USDT market prices. Use BigDecimal and strings for amount
calculations; do not use double or float.
platformUserId is the 6MM external user ID. It is currently a 10-digit numeric
string, for example:
1188041528
Rules:
- Store it as a string, not as an integer.
- Do not generate, decode, or infer meaning from it.
- Use your own partner-side user ID as
agentUserId. - Persist the relationship among
agentUserId,platformUserId, andagentOrderNo.
Bind creates or fetches the relationship between a partner user and a 6MM platform user. Call it when a user first enters the trading flow or before the first transfer into 6MM.
import com.sixmm.agent.model.BindRequest;
import com.sixmm.agent.model.BindResponse;
BindResponse resp = client.bind(
BindRequest.of("agent-user-001")
.withUsername("alice")
.withExt("{\"source\":\"web\"}"));
System.out.println(resp.platformUserId);
System.out.println(resp.bindStatus);
System.out.println(resp.isSimulatedUser);Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
agentUserId |
string | Yes | Unique partner-side user ID |
username |
string | No | Partner-side display name used as the platform user's nickname |
ext |
string | No | Extension field. JSON string is recommended |
Response fields:
| Field | Type | Description |
|---|---|---|
platformUserId |
string | 6MM external user ID |
bindStatus |
string | Usually BOUND |
isSimulatedUser |
boolean | Whether this is a simulated user |
Use transfer for fixed amount transfers. Direction.IN means transferring
from the partner platform into 6MM. Direction.OUT means transferring from 6MM
back to the partner platform.
Use strings or BigDecimal for amounts. Do not use double or float.
import com.sixmm.agent.model.Direction;
import com.sixmm.agent.model.TransferRequest;
import com.sixmm.agent.model.TransferResponse;
TransferResponse resp = client.transfer(TransferRequest.fixed(
"AGT-ORDER-1001",
"agent-user-001",
Direction.IN,
"USDT",
"10.00"));
System.out.println(resp.orderNo);
System.out.println(resp.orderStatus);
System.out.println(resp.agentUserId);
System.out.println(resp.platformUserId);TransferResponse resp = client.transfer(TransferRequest.fixedByPlatformUserId(
"AGT-ORDER-1002",
"1188041528",
Direction.OUT,
"USDT",
"5.00"));If both IDs are provided, the service validates that they point to the same bound user.
TransferRequest req = TransferRequest
.fixed("AGT-ORDER-1003", "agent-user-001", Direction.IN, "USDT", "20.00")
.withPlatformUserId("1188041528");
TransferResponse resp = client.transfer(req);Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
agentOrderNo |
string | Yes | Globally unique partner order number |
agentUserId |
string | Conditionally | Required when platformUserId is absent |
platformUserId |
string | Conditionally | Required when agentUserId is absent |
direction |
enum | Yes | IN or OUT |
currency |
string | No | Filled from defaultCurrency when absent |
amount |
string | Yes | Decimal amount string |
Response fields:
| Field | Type | Description |
|---|---|---|
orderNo |
string | Platform order number |
orderStatus |
string | SUCCESS, FAILED, PROCESSING, etc. |
agentUserId |
string | Partner-side user ID |
platformUserId |
string | 6MM external user ID |
After transfer is called, the Agent service synchronously calls the trading
core on the main path. In most cases, the API response already contains the
synchronous trading-core result.
| Result | Meaning | Partner action |
|---|---|---|
SUCCESS |
Transfer succeeded | Mark local order as successful |
FAILED |
Transfer was rejected or failed | Save the failure reason and show it when appropriate |
PROCESSING |
Trading core timeout or network uncertainty | Do not retry with a new order number. Wait for webhook or call queryOrder |
Idempotency requirements:
- Use one
agentOrderNofor one business transaction. - If HTTP times out or the network fails, query the same
agentOrderNofirst. - Webhooks may be retried. Deduplicate them by idempotency key.
transferAllOut moves the user's withdrawable 6MM-side balance back to the
partner platform.
import com.sixmm.agent.model.TransferAllOutRequest;
import com.sixmm.agent.model.TransferAllOutResponse;
TransferAllOutResponse resp = client.transferAllOut(
TransferAllOutRequest.of("AGT-ORDER-2001", "agent-user-001", "USDT"));
System.out.println(resp.orderStatus);
System.out.println(resp.amount);By platformUserId:
TransferAllOutResponse resp = client.transferAllOut(
TransferAllOutRequest.byPlatformUserId("AGT-ORDER-2002", "1188041528", "USDT"));amount in the response is the actual transferred amount.
Reverse is used to compensate a successful transfer order when the backend supports the reverse flow. Typical cases include partner local order exceptions or manual reconciliation rollback.
import com.sixmm.agent.model.ReverseOrderRequest;
import com.sixmm.agent.model.ReverseOrderResponse;
ReverseOrderResponse resp = client.reverse(ReverseOrderRequest.of(
"AGT-ORDER-1001",
"REV-ORDER-1001",
"partner order rollback"));
System.out.println(resp.orderStatus);Fields:
| Field | Type | Required | Description |
|---|---|---|---|
origOrderNo |
string | Yes | Original transfer order number |
reverseOrderNo |
string | Yes | Globally unique reverse order number |
reverseReason |
string | Yes | Reverse reason |
Notes:
- Reverse is not a normal cancel operation.
- Reverse orders must also be idempotent by order number.
- After an original order is reversed, webhook may push the original order's
REVERSEDfinal state.
import com.sixmm.agent.model.OrderQueryType;
import com.sixmm.agent.model.QueryOrderRequest;
import com.sixmm.agent.model.QueryOrderResponse;
QueryOrderResponse resp = client.queryOrder(
QueryOrderRequest.of("AGT-ORDER-1001", OrderQueryType.TRANSFER_IN));
System.out.println(resp.status);
System.out.println(resp.failReason);Supported orderType values:
TRANSFER_INTRANSFER_OUT
Common response fields:
| Field | Type | Description |
|---|---|---|
orderType |
string | Order type |
orderNo |
string | Partner order number |
status |
string | Order status |
direction |
string | IN or OUT |
transferMode |
string | FIXED_AMOUNT or ALL_OUT |
currency |
string | Currency |
amount |
string | Amount |
agentUserId |
string | Partner-side user ID |
platformUserId |
string | 6MM external user ID |
failReason |
string | Failure reason |
createdAt |
string | Creation time |
completedAt |
string | Completion time |
import com.sixmm.agent.model.ListOrdersRequest;
import com.sixmm.agent.model.ListOrdersResponse;
ListOrdersRequest req = ListOrdersRequest.page(1, 20);
req.orderType = "TRANSFER_IN";
req.status = "SUCCESS";
req.startTime = "2026-06-01T00:00:00Z";
req.endTime = "2026-06-16T00:00:00Z";
ListOrdersResponse resp = client.listOrders(req);
System.out.println(resp.total);
resp.orders.forEach(order -> System.out.println(order.orderNo));Pagination recommendations:
pagestarts from 1.- Keep
pageSizeat or below 100. - For reconciliation jobs, page by time window and deduplicate by
orderNo.
import com.sixmm.agent.model.QueryAccountRequest;
import com.sixmm.agent.model.QueryAccountResponse;
QueryAccountResponse resp = client.queryAccount(QueryAccountRequest.of("USDT"));
System.out.println(resp.agentCode);
System.out.println(resp.agentStatus);
resp.assets.forEach(asset -> {
System.out.println(asset.currency);
System.out.println(asset.depositBalance);
});When currency is absent, the SDK uses defaultCurrency.
import com.sixmm.agent.model.QueryUserAssetsRequest;
import com.sixmm.agent.model.QueryUserAssetsResponse;
QueryUserAssetsResponse resp = client.queryUserAssets(
QueryUserAssetsRequest.of("1188041528"));
System.out.println(resp.walletBalance);
System.out.println(resp.availableBalance);
System.out.println(resp.version);Fields:
| Field | Type | Description |
|---|---|---|
walletBalance |
string | Wallet balance |
frozenMargin |
string | Frozen margin |
usedMargin |
string | Used margin |
availableBalance |
string | Available balance |
isolatedMargin |
string | Isolated margin |
version |
int64 | Asset version |
isSimulatedUser |
boolean | Whether this is a simulated user |
Direct entry URL is for redirect mode. A partner user clicks a button on the partner site, opens 6MM frontend, and is automatically logged in.
import com.sixmm.agent.model.CreateEntryUrlRequest;
import com.sixmm.agent.model.CreateEntryUrlResponse;
CreateEntryUrlResponse resp = client.createEntryUrl(
CreateEntryUrlRequest.of("agent-user-001")
.withRedirectPath("/en/futures/BTCUSDT?tradingMode=real")
.withReturnUrl("https://partner.example.com/return#markets"));
System.out.println(resp.webUrl);
System.out.println(resp.expireAt);Field rules:
| Field | Description |
|---|---|
redirectPath |
6MM frontend relative path. It must start with /, for example /en/futures/BTCUSDT?tradingMode=real |
returnUrl |
Partner absolute URL used when the user exits 6MM frontend. Only http and https are allowed |
expireAt |
Entry ticket expiration time as a Unix timestamp in seconds |
The example opens the perpetual futures page in real mode. Use tradingMode=demo for simulated trading and explicitly select SIMULATED in the corresponding wallet requests. Creating an entry URL authenticates the user; it does not transfer funds or select the wallet environment.
Security requirements:
webUrlcontains a one-time ticket. Use it immediately and do not store it long term.- If the entry URL expires or has been used, generate a new one from the partner site.
returnUrlmust not bejavascript:, a relative path, or a URL with userinfo.
Embed token is for Trading Widget SDK partner-token + tokenProvider mode. The
browser calls the partner backend, and the partner backend calls this Java SDK
to create an embedToken.
import com.sixmm.agent.model.CreateEmbedTokenRequest;
import com.sixmm.agent.model.CreateEmbedTokenResponse;
CreateEmbedTokenResponse resp = client.createEmbedToken(
CreateEmbedTokenRequest.of("agent-user-001", "tw_abc123")
.withSymbol("ETHUSDT"));
System.out.println(resp.embedToken);
System.out.println(resp.expireAt);Integration requirements:
channelIdmust use the value passed by the Trading Widget SDK.symbolis optional, but it is recommended to pass the current initial symbol.embedTokenis short-lived and one-time. Do not put it into URL query strings.- The partner frontend must never hold
apiSecret. expireAtis a Unix timestamp in seconds, not a TTL.
Partner backend endpoint example:
@PostMapping("/api/trading/embed-token")
public EmbedTokenView createEmbedToken(@RequestBody EmbedTokenRequest request,
PartnerSession session) {
String agentUserId = session.getAgentUserId();
CreateEmbedTokenResponse resp = agentClient.createEmbedToken(
CreateEmbedTokenRequest.of(agentUserId, request.getChannelId())
.withSymbol(request.getSymbol()));
return new EmbedTokenView(resp.embedToken, resp.expireAt, request.getChannelId());
}6MM pushes a webhook to the configured webhookUrl when a transfer order reaches
a final state. The SDK provides signature verification and idempotency key
helpers.
import com.sixmm.agent.WebhookVerifier;
boolean ok = WebhookVerifier.verify(
"your-api-secret",
timestampHeader,
nonceHeader,
rawRequestBodyBytes,
signatureHeader);
if (!ok) {
throw new SecurityException("invalid 6mm webhook signature");
}
String idempotencyKey = WebhookVerifier.idempotencyKey(rawRequestBodyBytes);Webhook headers:
| Header | Description |
|---|---|
X-Agent-Timestamp |
Unix timestamp in seconds |
X-Agent-Nonce |
Nonce |
X-Agent-Signature |
HMAC-SHA256 signature |
Signature payload:
timestamp + nonce + rawBody
Partner-side recommendations:
- Reject requests whose timestamp differs from server time by more than 5 minutes.
- Cache nonce values to prevent replay.
- Deduplicate by
WebhookVerifier.idempotencyKey(rawBody). - Return HTTP 2xx after successful processing. Non-2xx responses may trigger retries.
Webhook events:
event |
Trigger | Common targetStatus |
|---|---|---|
transfer.completed |
Fixed amount transfer or transfer-all-out reaches final state. Original order may also emit this after reverse | SUCCESS / FAILED / REVERSED |
reverse.completed |
Reverse order reaches final state | SUCCESS / FAILED |
transfer.dead |
System retries cannot confirm the final state and manual intervention is required | DEAD |
platformUserId in webhook payload is the same value returned by bind.
agentUserId is the partner-side user ID. Use
orderType + orderId + targetStatus or the SDK-generated idempotencyKey for
deduplication.
SDK exceptions are split into two categories:
| Exception | Scenario | Suggested handling |
|---|---|---|
AgentApiException |
HTTP status is not 2xx, or Agent response code != 0 |
Read getHttpStatus(), getCode(), and getResponseBody() and treat it as a business/API failure |
AgentSdkException |
Network, serialization, configuration, or signing failure | Log it and treat it as a system exception |
Example:
import com.sixmm.agent.AgentApiException;
import com.sixmm.agent.AgentSdkException;
try {
TransferResponse resp = client.transfer(TransferRequest.fixed(
"AGT-ORDER-1001", "agent-user-001", Direction.IN, "USDT", "10.00"));
// Update the local order according to resp.orderStatus.
} catch (AgentApiException e) {
// Business rejection or HTTP error.
log.warn("6mm agent api rejected request, httpStatus={}, code={}, body={}",
e.getHttpStatus(), e.getCode(), e.getResponseBody());
} catch (AgentSdkException e) {
// Local SDK error or network error.
log.error("6mm agent sdk request failed", e);
}1. User logs in to the partner site.
2. Partner backend calls bind with agentUserId.
3. Partner stores the agentUserId and platformUserId relationship.
4. User clicks the trading entry.
5. Redirect mode: call createEntryUrl and open webUrl in the browser.
6. Embed mode: Trading Widget calls tokenProvider, and partner backend calls createEmbedToken.
1. Partner creates a unique agentOrderNo.
2. Partner calls transfer(Direction.IN).
3. If SUCCESS is returned, mark the local order as successful.
4. If PROCESSING is returned, wait for webhook or poll queryOrder.
5. If FAILED is returned or AgentApiException is thrown, handle it as failed.
1. Partner creates a unique agentOrderNo.
2. Fixed amount withdraw: call transfer(Direction.OUT).
3. Full withdraw: call transferAllOut.
4. Confirm the final result by orderStatus, webhook, or queryOrder.
Partner backend logs should include at least:
agentOrderNoagentUserIdplatformUserIddirectioncurrencyamountorderStatusAgentApiException.coderequestIdif present in the response body
Do not log full apiSecret, full signatures, or sensitive user information.
| Check | Expected result |
|---|---|
client.version() |
Returns service name, version, and commit information |
bind |
Returns platformUserId and BOUND |
Small transfer IN |
Returns SUCCESS or can be confirmed successful through queryOrder |
Small transfer OUT |
Returns SUCCESS or can be confirmed successful through queryOrder |
Duplicate agentOrderNo |
Does not create duplicate fund movement |
| Webhook signature verification | Valid signature passes; tampered body fails |
| Webhook idempotency | Duplicate webhook delivery does not create duplicate accounting |
createEntryUrl |
Browser can open and enter the 6MM frontend |
createEmbedToken |
Trading Widget can complete embedded authentication |
listSupportedFiatCurrencies |
Returns a non-empty source list with USDT as target |
queryExchangeRates |
Returns REFERENCE_ONLY, a valid snapshot, and requested currencies |
No. Store it as a string. It is currently numeric-looking, but the external contract is string.
Do not do that immediately. Query the original agentOrderNo first. Only create
a new order after the original order is confirmed absent or failed and your
business flow explicitly decides to retry.
No. It means the final result is still uncertain. Wait for webhook or query the order actively.
To avoid floating-point precision issues. Java business code may use
BigDecimal; the SDK serializes it as a plain decimal string.
That is expected retry behavior. Deduplicate by orderType:orderId:targetStatus
or the SDK idempotencyKey.
No. Browsers must not hold apiSecret. The correct flow is browser -> partner
backend -> createEmbedToken.
Run from the SDK repository root:
mvn test
mvn packageIf a business project uses local installation:
mvn clean installThese methods are available in production. Confirm availability separately for other endpoints provided by 6MM. All six methods use signed POST requests under /v1/agent/perpetual.
| Method | Route | Player selection |
|---|---|---|
listCurrentPerpetualOrders |
/orders/current |
Optional for NORMAL; required for CONDITIONAL |
listPerpetualOrderHistory |
/orders/history |
Optional for NORMAL; required for CONDITIONAL |
listPerpetualTrades |
/trades |
Required |
listCurrentPerpetualPositions |
/positions/current |
Optional |
listPerpetualPositionHistory |
/positions/history |
Optional |
listPerpetualLedger |
/account/ledger |
Optional |
platformUserIds contains 1–100 unique public platform user IDs (10-digit strings), never internal user IDs. Omitting this field on supported routes selects the authenticated partner's direct players; an explicit empty array is invalid. Order queries require orderCategory (NORMAL or CONDITIONAL). The partner/agent ID is derived from authentication, not supplied as a filter.
Historical filters use Unix milliseconds and [startTime, endTime): order creation time, trade execution time, position closing time, or ledger record creation time respectively. Current orders/positions do not accept historical time filters. Order timestamps describe record creation/update. Default page size is 500, maximum 1000. Keep filters unchanged and pass nextCursor until hasMore is false, even if an intermediate page is empty. Pagination does not provide a cross-page snapshot or a guaranteed incremental event feed.
import com.sixmm.agent.model.PerpetualTradesRequest;
import com.sixmm.agent.model.PerpetualResponse;
import java.util.Arrays;
PerpetualTradesRequest request = new PerpetualTradesRequest();
request.platformUserIds = Arrays.asList("1000000042", "1000000043");
request.limit = 500;
PerpetualResponse page;
do {
page = client.listPerpetualTrades(request);
// 处理成功返回的明细,并按业务需要持久化。
request.cursor = page.data.nextCursor;
if (Boolean.TRUE.equals(page.data.hasMore)) Thread.sleep(600);
} while (Boolean.TRUE.equals(page.data.hasMore));The SDK signs arrays as compact JSON and retains record IDs/amounts as strings. Current NORMAL orders omit leverage and margin mode. Ledger records use their individual detail ID and may share a ledger ID. Missing fields are not zero values. See the response field reference (Chinese) for field types, resource-specific meanings, statuses and omission rules.
All six routes share the partner's rate limit: default 2 requests/second, burst 4, plus concurrency protection. Business error 6905 indicates frequency limiting; 6904 indicates unavailability/concurrency protection. SDK calls throw AgentApiException and do not retry automatically. On an explicit bounded retry, keep the same cursor/filters; calling the SDK again generates a fresh timestamp, nonce and signature. Coordinate throttling across your processes; per-loop sleeps alone do not coordinate concurrent callers.
Funding/transfer environment selectors remain available on their existing methods. Do not add environment to perpetual-query requests: it is not part of these six contracts. Availability, source retention and asynchronous ingestion determine which history can be returned; a successful page does not prove complete financial reconciliation.