Skip to content

About

6MM Agent Java SDK for partner integration

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

6MM Agent Java SDK

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).

Requirements

  • Java 8+
  • Maven 3.9+

What The SDK Covers

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

Configuration

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 apiSecret in 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 apiSecret to browsers, apps, mini programs, or frontend source code.

Maven Coordinates

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 install

After 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 And Simulated Trading

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.

Client Initialization

Plain Java

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());

Spring Boot

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}

Automatic Signing Fields

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:

  1. Exclude sign.
  2. Exclude empty values.
  3. Sort keys by ASCII order.
  4. Join as k=v&k2=v2.
  5. Calculate HMAC-SHA256 hex with apiSecret.

Normal business code should not calculate signatures or manually set agentCode, timestamp, nonce, or sign.

FX Reference Rates

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.

User ID Rules

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, and agentOrderNo.

Bind User

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

Fixed Amount Transfer

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.

Transfer By agentUserId

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);

Transfer By platformUserId

TransferResponse resp = client.transfer(TransferRequest.fixedByPlatformUserId(
        "AGT-ORDER-1002",
        "1188041528",
        Direction.OUT,
        "USDT",
        "5.00"));

Provide Both IDs

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

Order Confirmation And Idempotency

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 agentOrderNo for one business transaction.
  • If HTTP times out or the network fails, query the same agentOrderNo first.
  • Webhooks may be retried. Deduplicate them by idempotency key.

Transfer All Out

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 Order

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 REVERSED final state.

Query Order

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_IN
  • TRANSFER_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

List Orders

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:

  • page starts from 1.
  • Keep pageSize at or below 100.
  • For reconciliation jobs, page by time window and deduplicate by orderNo.

Query Partner Account

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.

Query User Assets

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

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:

  • webUrl contains 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.
  • returnUrl must not be javascript:, a relative path, or a URL with userinfo.

Trading Widget Embed Token

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:

  • channelId must use the value passed by the Trading Widget SDK.
  • symbol is optional, but it is recommended to pass the current initial symbol.
  • embedToken is short-lived and one-time. Do not put it into URL query strings.
  • The partner frontend must never hold apiSecret.
  • expireAt is 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());
}

Webhook Verification

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.

Error Handling

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);
}

Recommended Business Flows

First Trading Entry

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.

Deposit Into 6MM

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.

Withdraw Back To Partner

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.

Logging And Troubleshooting

Partner backend logs should include at least:

  • agentOrderNo
  • agentUserId
  • platformUserId
  • direction
  • currency
  • amount
  • orderStatus
  • AgentApiException.code
  • requestId if present in the response body

Do not log full apiSecret, full signatures, or sensitive user information.

Integration Checklist

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

FAQ

Can platformUserId be stored as long?

No. Store it as a string. It is currently numeric-looking, but the external contract is string.

Can I retry with a new order number after timeout?

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.

Is PROCESSING a failure?

No. It means the final result is still uncertain. Wait for webhook or query the order actively.

Why should amounts be strings?

To avoid floating-point precision issues. Java business code may use BigDecimal; the SDK serializes it as a plain decimal string.

What if webhook is received multiple times?

That is expected retry behavior. Deduplicate by orderType:orderId:targetStatus or the SDK idempotencyKey.

Can Trading Widget call Agent API directly from the browser?

No. Browsers must not hold apiSecret. The correct flow is browser -> partner backend -> createEmbedToken.

Local Test Commands

Run from the SDK repository root:

mvn test
mvn package

If a business project uses local installation:

mvn clean install

Perpetual queries (0.3.0)

These 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.

About

6MM Agent Java SDK for partner integration

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages