REST API
Environment Information
| Environment | Base URL |
|---|---|
| Production | https://api-studio.r25.xyz |
Changelog
Update dates use YYYY-MM-DD, with the latest date first. Historical entries use documentation commit dates and do not indicate API deployment dates.
| Updated On | Changes |
|---|---|
| 2026-10-22 | Added: GET /api/r25/assets/list — Vault asset catalog query (Section 9.10), GET /api/r25/hyperliquid/assets/list — Hyperliquid asset list query (Section 9.11) |
1. Document Scope and Capability Overview
This document is intended for external partners integrating the OpenAPI query endpoints, Trading REST write endpoints, and Webhooks. It describes the endpoints available in the current version, the signature scheme, and the Webhook payloads. Hosts, Client IDs, and signatures in the examples are placeholders; replace them with values assigned by the platform or agreed by both parties.
Current capabilities include:
- Standard Vault: query a single Vault's metadata, the list of published Vaults, NAV history, and current asset positions; call the four ERC4626 preview operations.
- Rebate channel distribution: query cumulative commission and attribution flows.
- Transaction records: unified query of on-chain transaction events that have already been integrated, filtered by wallet address, Vault contract address, and other conditions.
- Trading REST: create orders, cancel orders, and close positions over HTTP;
HYPERLIQUIDandHABITTRADEare currently integrated. - Webhook: receive configured Vault and 7 types of Rebate change notifications;
eventTypeidentifies the business event.
2. Base URL, Content-Type, and Time / Number / Null Conventions
2.1 General Conventions
- Base URL: choose the corresponding address from the environment information at the beginning of this document.
- GET endpoints: all parameters are passed in the URL query string; no request body is sent.
- POST endpoints: the request body is JSON, using
Content-Type: application/json. - API responses: JSON, using the common response envelope defined in Section 4.
- URL query strings should be UTF-8 percent-encoded; for signing, the Canonical Query must additionally be generated as described in Section 3.
- This document only describes the APIs and Webhook callback protocol available to partners.
2.2 Time Conventions
- The
timestampin the unified response is a Unix timestamp in milliseconds. - Partners should use Unix seconds for the authentication header
X-Timestamp. Unix milliseconds andyyyy-MM-dd HH:mm:ssin the platform time zone are also accepted. - The
tsfield in the Trading REST request body is a Unix timestamp in milliseconds and must be close to the current server time; a request older than 10 seconds before the server's current time will be rejected. It is a separate field from the authentication headerX-Timestamp, and both must be provided. - The
datefield of Standard Vault NAV history is a millisecond timestamp string corresponding to 00:00 UTC of the given day. - The
requestBlockTimeandsettleBlockTimeof transaction records are in epoch seconds. - The Webhook header
X-Timestampis in Unix seconds. - The
occurredAtfield in a Webhook payload is an ISO 8601 offset time converted toAsia/Hong_Kong; the current offset is+08:00.
2.3 Number and Null Conventions
- On-chain amounts or quantities exposed as
Stringmust be handled as strings; do not convert them to a JavaScriptNumberor any type that may lose precision. - Decimal values are output as JSON numbers, e.g.
1.025,125000000, and should be parsed with an arbitrary-precision decimal type. - Unless otherwise stated, asset price fields are denominated in USD per asset unit; position weight, yield, and fee rate fields are expressed as percentages, e.g.
20means20%. - In Rebate commission responses, rate numbers represent percentages; asset quantity strings represent the raw on-chain asset amounts and are not subject to precision conversion, USD valuation, or cross-asset aggregation.
- All response fields documented here are included; fields with no available value are returned as
null.
3. Ed25519 V2 Authentication and Signing
3.1 Required Authentication Headers
All external endpoints in this document require the following headers:
| Header | Required | Description |
|---|---|---|
X-Client-Id | Yes | The unique partner identifier assigned by the platform and associated with the partner's Ed25519 public key. |
X-Timestamp | Yes | Request time. Unix seconds recommended; Unix milliseconds or yyyy-MM-dd HH:mm:ss are also accepted. |
X-Signature | Yes | The Ed25519 signature encoded as a hex string, exactly 128 hexadecimal characters, i.e. 64 bytes. |
Each X-Client-Id is associated with a 32-byte raw Ed25519 public key; the partner signs with the corresponding private key. Never expose the private key to the platform or to logs.
3.2 String to Sign
The string to sign is exactly:
METHOD\nPATH\nCANONICAL_QUERY\nTIMESTAMP\nSHA256_HEX(BODY)
Rules:
METHOD: the HTTP method in uppercase, e.g.GET,POST.PATH: the URL path only, excluding the host and query string, e.g./api/r25/standard-vault/vaultList.CANONICAL_QUERY: normalized as in the next section. When there is no query, use an empty string, but the corresponding empty line must be preserved.TIMESTAMP: must be exactly the same as the original text of theX-Timestamprequest header.SHA256_HEX(BODY): compute SHA-256 over the actually sent raw body UTF-8 bytes, then output lowercase hex. GET sends no body; the digest of empty bytes ise3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
For example:
GET
/api/r25/standard-vault/vaultList
pageNumber=1&pageSize=10
1786588800
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Sign the complete UTF-8 string above with Ed25519, encode the 64-byte signature as a 128-character hex string, and put it in X-Signature.
3.3 Canonical Query
Canonical Query generation rules:
- Each endpoint accepts only the Query keys listed in its request parameters. Do not add Query keys to an endpoint that declares none. The server determines the allowed keys from the endpoint's parameter declarations.
- Sort by key in ascending lexicographic order.
- Both the key and the value are percent-encoded per RFC 3986 in UTF-8;
A-Z a-z 0-9 - _ . ~are not encoded, spaces must be encoded as%20, and+must not be used. - Each entry is composed as
key=value, then joined with&. - Repeating the same key makes the request invalid.
- The query parameters sent in the URL must exactly match those used to build the Canonical Query, including their decoded values. Do not add parameters that the endpoint does not declare.
3.4 Time Window and Body Consistency
- The accepted server-side time skew is ±300 seconds around the current time.
yyyy-MM-dd HH:mm:ssis interpreted in the platform time zone. To avoid time-zone discrepancies, partners should always use Unix seconds.- A POST signature must be based on the final actually sent raw JSON bytes. Any change in field order, whitespace, line breaks, or escaping changes the body digest.
- On retry, regenerate the current timestamp and signature.
3.5 Java 17+ Complete Signing Example
The following example demonstrates how to read a standard PKCS#8 PEM private key safely held by the partner, generate the Canonical Query, build the five-part string to sign, perform the Ed25519 signature, and issue a GET request. Ed25519 is built into JDK 17; BouncyCastle is not required.
The query in the example must use only the keys declared by the target endpoint. The code uses the same Canonical Query to build both the actual URL and the string to sign.
package client.sign;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HexFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
public final class AkSkSigner {
private AkSkSigner() {
}
public static PrivateKey loadPrivateKeyFromPemFile(Path pemFile) throws Exception {
return loadPrivateKeyFromPem(Files.readString(pemFile, StandardCharsets.UTF_8));
}
public static PrivateKey loadPrivateKeyFromPem(String pem) throws Exception {
String base64 = pem
.replaceAll("-----BEGIN[^-]*-----", "")
.replaceAll("-----END[^-]*-----", "")
.replaceAll("\\s", "");
byte[] der = Base64.getDecoder().decode(base64);
return KeyFactory.getInstance("Ed25519")
.generatePrivate(new PKCS8EncodedKeySpec(der));
}
/** RFC3986: only A-Za-z0-9-_.~ are kept; other characters are converted to uppercase %XX per UTF-8 byte. */
static String rfc3986(String value) {
StringBuilder out = new StringBuilder();
for (byte b : value.getBytes(StandardCharsets.UTF_8)) {
int c = b & 0xff;
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || c == '-' || c == '_'
|| c == '.' || c == '~') {
out.append((char) c);
} else {
out.append('%').append(String.format("%02X", c));
}
}
return out.toString();
}
/** Keys in ascending order, single value, joined as k=v with &; returns an empty string when there are no parameters. */
static String canonicalQuery(Map<String, String> params) {
if (params == null || params.isEmpty()) {
return "";
}
TreeMap<String, String> sorted = new TreeMap<>(params);
List<String> pairs = new ArrayList<>();
sorted.forEach((key, value) -> pairs.add(
rfc3986(key) + "=" + rfc3986(value == null ? "" : value)));
return String.join("&", pairs);
}
/** SHA-256 lowercase hex, fixed at 64 characters. */
static String sha256Hex(byte[] data) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return HexFormat.of().formatHex(digest.digest(data));
} catch (Exception e) {
throw new IllegalStateException("SHA-256 unavailable", e);
}
}
static String buildStringToSign(String method, String path, String canonicalQuery,
String timestamp, byte[] body) {
return method.toUpperCase(Locale.ROOT)
+ "\n" + path
+ "\n" + canonicalQuery
+ "\n" + timestamp
+ "\n" + sha256Hex(body);
}
/** Sign with the Ed25519 private key, returning 128 lowercase hex characters. */
static String signHex(PrivateKey privateKey, String stringToSign) throws Exception {
Signature signer = Signature.getInstance("Ed25519");
signer.initSign(privateKey);
signer.update(stringToSign.getBytes(StandardCharsets.UTF_8));
return HexFormat.of().formatHex(signer.sign());
}
public static HttpResponse<String> callSigned(
String baseUrl, String clientId, PrivateKey privateKey,
String method, String path,
Map<String, String> query, String jsonBody) throws Exception {
byte[] body = jsonBody == null
? new byte[0]
: jsonBody.getBytes(StandardCharsets.UTF_8);
String timestamp = String.valueOf(System.currentTimeMillis());
String canonicalQuery = canonicalQuery(query);
String stringToSign = buildStringToSign(
method, path, canonicalQuery, timestamp, body);
String signature = signHex(privateKey, stringToSign);
String url = baseUrl + path
+ (canonicalQuery.isEmpty() ? "" : "?" + canonicalQuery);
HttpRequest.Builder builder = HttpRequest.newBuilder(URI.create(url))
.header("X-Client-Id", clientId)
.header("X-Timestamp", timestamp)
.header("X-Signature", signature)
.header("Content-Type", "application/json");
builder = "GET".equalsIgnoreCase(method)
? builder.GET()
: builder.method(method.toUpperCase(Locale.ROOT),
HttpRequest.BodyPublishers.ofByteArray(body));
return HttpClient.newHttpClient().send(
builder.build(), HttpResponse.BodyHandlers.ofString());
}
public static void main(String[] args) throws Exception {
PrivateKey privateKey = loadPrivateKeyFromPemFile(
Path.of("/path/to/<client-id>-private-key.pem"));
String baseUrl = "https://<api-host>";
String clientId = "<client-id>";
// Example 1: GET + Query.
Map<String, String> query = new LinkedHashMap<>();
query.put("pageNumber", "1");
query.put("pageSize", "20");
HttpResponse<String> getResponse = callSigned(
baseUrl, clientId, privateKey,
"GET", "/api/r25/standard-vault/vaultList", query, null);
System.out.println("[GET] " + getResponse.statusCode()
+ " " + getResponse.body());
}
}
4. Common Response Envelope and External Business Error Codes
4.1 Response Envelope
Successful response:
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {}
}
Failed response:
{
"code": "-1005",
"message": "pageSize must not exceed 100",
"timestamp": 1786588800123,
"data": {}
}
Field descriptions:
| Field | Type | Description |
|---|---|---|
code | String | Business response code; success is "200". Generic failures use the string form of a negative number; Trading REST business failures use uppercase enum strings. |
message | String | SUCCESS on success; an error explanation on failure, sometimes with the specific reason appended. |
timestamp | Long | The Unix timestamp in milliseconds at which the server generated the response. |
data | Any JSON value | Business data on success; null when the success data is empty. On failure it is usually an empty object {}; a Trading REST Vault permission failure returns deniedVaultAddresses. |
The response does not contain a success field. The HTTP status of both successful and failed business responses remains 200; partners must determine the business result from code in the JSON and must not rely on the HTTP status alone.
4.2 Current Business Error Codes
| code | Default message | Meaning |
|---|---|---|
-1001 | auth headers missing | Missing authentication headers; also used to reject duplicate query keys. The specific message explains the reason. |
-1002 | timestamp expired or invalid | The timestamp cannot be parsed or falls outside the ±300 second window. |
-1003 | invalid access key | The X-Client-Id is unknown, or no public key is currently available on the server. |
-1004 | signature mismatch | The Ed25519 signature does not match, or the signature hex format/length is incorrect. |
-1005 | form validation err | Query/JSON field validation failed, a required query parameter is missing, or a query key is not in the signature allow list. The specific message may describe the validation failure. |
-1006 | auth failed | Authentication failed. |
-1007 | too many requests | The request rate limit was triggered. |
-1008 | vault not permitted | The Vault address is blank, or the current partner identity is not permitted to access the specified Vault; an unknown address outside the accessible set also returns this code. |
-1017 | request replayed | An identical signed request was resent within the authentication time window. |
-1010 | query metadata failed | The metadata query failed; this code also applies when a Standard Vault address passes the access check but no metadata is found. |
-1012 | query nav history failed | The Standard Vault NAV history query failed, or the returned data does not conform to the contract. |
-1019 | query channel distribution failed | The Rebate query failed; when a valid business error message is available, that message takes precedence. |
-1020 | preview contract call failed | The preview calculation failed. |
-1021 | query positions failed | The Standard Vault current positions query failed or the downstream response violates the contract. |
-1022 | query vault events failed | The Vault events query failed. |
-1026 | query hyperliquid account failed | The Curator Vault address does not resolve to one ID, the downstream account query fails, or its response violates the contract. |
-1027 | asset configuration failed | The asset or Vault cannot be identified uniquely, or the configuration request is rejected. Details may appear in message. |
-1028 | asset configuration result unknown | The configuration outcome cannot be confirmed. Check the actual state before retrying. |
-1029 | query assets failed | The asset list query failed or the response did not match the API contract. |
-5000 | server error | An unexpected service error occurred. |
When a Rebate query returns a recognizable business error, the response uses the corresponding code above and includes the business error message in message when one is available. Otherwise, the default message in the table is used. Network timeouts and service errors return -5000 with server error.
After a Trading REST request passes common authentication, JSON parsing, and rate limiting, business failures use the following string code:
| code | Meaning | Retry advice |
|---|---|---|
INVALID_REQUEST | The request envelope, required fields, enums, values, or ranges are invalid. | Correct the request and retry. |
VAULT_NOT_PERMITTED | The current X-Client-Id has no permission to operate on the vaultAddress, or the address cannot be resolved to a Vault. | Do not retry; verify the authorization relationship. |
INVALID_EXCHANGE | exchange is missing or is not HYPERLIQUID / HABITTRADE. | Correct the request and retry. |
FEATURE_UNSUPPORTED | The current exchange does not support the operation, e.g. HabitTrade order cancellation, or Hyperliquid requests that explicitly specify closeMode=PARTIAL. | Do not retry with the same parameters. |
INVALID_PRICE_TICK | The price does not conform to the current exchange's price precision configuration. | Correct to a valid price precision and retry. |
INVALID_SIZE_STEP | The quantity does not conform to the current exchange's quantity precision configuration. | Correct to a valid quantity precision and retry. |
EXCHANGE_REJECTED | The exchange returned a business rejection or failure result. | Correct according to the message; do not retry unconditionally. |
UPSTREAM_RESULT_UNKNOWN | A write request timed out or errored; the server cannot confirm whether the exchange accepted it. | Do NOT retry directly; query the order or position first to confirm the result. |
INTERNAL_ERROR | The request could not be processed because of an unexpected service error. | Retain the request information and contact the platform for investigation. |
4.3 Request Rate Limits
The production limits below apply to the listed operations. Other rate-limited REST endpoints in this guide use the default row. Each operation has a separate quota for the authenticated X-Client-Id and for the request IP address; an operation-specific limit replaces the default for that dimension.
| Operation | X-Client-Id limit | IP limit |
|---|---|---|
| Default: other rate-limited REST endpoints | 200 requests per 1 second | 20 requests per 1 second |
GET /api/r25/standard-vault/metadata | 1,000 requests per 1 second | 50 requests per 1 second |
GET /api/r25/channel-distribution/commission | 1,000 requests per 1 second | 1 request per 50 seconds |
GET /api/r25/standard-vault/events | 2,000 requests per 1 second | 100 requests per 1 second |
GET /api/r25/standard-vault/positions | 2,000 requests per 1 second | 100 requests per 1 second |
WebSocket message dispatch (including request, subscribe, and unsubscribe) | 2,000 messages per 1 second | 100 messages per 1 second |
- These are fixed windows that begin with the first accepted request or message for each interface rule and IP or Client ID. REST endpoints using the default limits still have separate counters; all WebSocket dispatch message types share one dispatch quota. Requests from different Client IDs sharing an IP also share that interface's IP quota; in particular, only one commission request from a shared IP can be accepted in a 50-second window.
- Both dimensions must have available quota. If either limit has been reached, the request or message is rejected without consuming quota in either dimension.
- A rate-limited HTTP request receives status
200and business code-1007with the default messagetoo many requests. ItsRetry-Afterresponse header gives the remaining wait in seconds, rounded up. - A rate-limited WebSocket message receives a
RATE_LIMITerror response withretryAfterMsin its message. The WebSocket quota applies to message dispatch, not to the connection handshake.
5. Endpoint Overview
| Category | Method | Path | Request location | Current status |
|---|---|---|---|---|
| Asset catalog | GET | /api/r25/assets/list | Query (exchange, net, symbol, tokenAddress, pageNumber, pageSize) | Queries the Vault asset table; downstream integration unverified; Client ID/IP rate limits apply |
| Asset catalog | GET | /api/r25/hyperliquid/assets/list | Query (symbol, productType, category, dex, page, pageSize) | Queries Hyperliquid assets, filters, and margin tables; downstream integration unverified; Client ID/IP rate limits apply |
| Asset catalog | POST | /api/r25/assets/configuration | JSON body (assets, vaultAddress, operation) | Batch-adds or removes Vault assets using ADD / REMOVE; Client ID/IP rate limits apply |
| Standard Vault | GET | /api/r25/standard-vault/metadata | Query | Available; vaultAddress is actually required |
| Standard Vault | GET | /api/r25/standard-vault/vaultList | Query (pageNumber, pageSize) | Available |
| Standard Vault | GET | /api/r25/standard-vault/events | Query (eventTime, pageNumber, pageSize) | Available |
| Standard Vault | GET | /api/r25/standard-vault/nav/history | Query | Available |
| Standard Vault | GET | /api/r25/standard-vault/positions | Query | Available; vaultAddress required |
| Standard Vault | GET | /api/r25/standard-vault/hyperliquid/account | Query (vaultAddress) | Route defined; awaiting the Hyperliquid downstream endpoint |
| Standard Vault Preview | GET | /api/r25/standard-vault/preview/mint | Query | Available |
| Standard Vault Preview | GET | /api/r25/standard-vault/preview/redeem | Query | Available |
| Standard Vault Preview | GET | /api/r25/standard-vault/preview/deposit | Query | Available |
| Standard Vault Preview | GET | /api/r25/standard-vault/preview/withdraw | Query | Available |
| Rebate | GET | /api/r25/channel-distribution/commission | Query | Available |
| Rebate | GET | /api/r25/channel-distribution/transactions | Query | Available |
| Rebate | GET | /api/r25/channel-distribution/merkle-proofs/batch | Query | Available |
| Transaction records | GET | /api/r25/standard-vault/transaction/records | Query | Unified transaction records entry |
| Trading REST | POST | /api/r25/trade/order/create | JSON Body | Available; supports Hyperliquid / HabitTrade |
| Trading REST | POST | /api/r25/trade/order/cancel | JSON Body | Hyperliquid only |
| Trading REST | POST | /api/r25/trade/position/close | JSON Body | Available; rules differ by exchange |
9. Standard Vault Endpoints
9.1 Common Metadata Response Structure
Standard Vault Metadata returns the layered VaultMetadataResponse structure. The response is grouped into basic info, audit report, dynamic metrics, transaction configuration, asset configuration, access control, contract configuration, risk configuration, and external integration configuration.
All documented fields are included in the response. Except where stated otherwise, a field is null when its value is unavailable or not applicable to that Vault type; fields are not automatically filled with "0", false, an empty string, or a zero address. An unavailable array may be null; an available array with no elements is [].
Top-level fields:
| Field | Type | Description |
|---|---|---|
vaultBasicInfo | Object | Vault basic information. |
auditReports | Array | Standard Vault audit reports in source order; zero or more entries, [] when not configured. HYB currently returns null. |
vaultMetrics | Object | Vault current dynamic metrics. |
transactionConfigInfo | Object | Vault subscription/redemption, limits, settlement, and fee configuration. |
assetConfig | Object | Share token and underlying asset configuration. |
accessControl | Object | Curator, Hyperliquid Manager, and subscription whitelist configuration. |
contractConfig | Object | Core contract and module contract configuration. |
riskConfig | Object | Vault risk configuration. |
prosperInfo | Object | Prosper external integration configuration. |
vaultBasicInfo fields:
| Field | Type | Description |
|---|---|---|
vaultName | String | Vault name; null when there is no data. |
vaultLogoUrl | String | Vault logo URL; null when there is no data. |
curationStrategyDescription | String | Strategy description configured by the Curator; null when there is no data. |
strategyDescription | String | Vault strategy description; returns null when unavailable. |
yieldStrategy | String | Yield strategy tag content, returned as a string without splitting; returns null when unavailable. |
chain | Object | Chain information of the Vault; fields are listed in the table below. |
offline | Boolean | Whether the Vault is offline; null when there is no data. |
deployTime | String | Contract deployment time in the format yyyy-MM-dd'T'HH:mm:ss with no time-zone offset. |
vaultBasicInfo.chain fields:
| Field | Type | Description |
|---|---|---|
chainId | String | Chain ID. |
chainName | String | Chain name. |
auditReports[] element fields:
| Field | Type | Description |
|---|---|---|
reportUrl | String | Audit report URL. |
provider | String | Audit provider name. |
reportType | String | Fixed value: SECURITY_AUDIT. |
vaultMetrics fields:
| Field | Type | Description |
|---|---|---|
tvl | String | Total value locked, represented as a decimal string. |
cFunding | String | Fund manager funding amount from the latest snapshot's seeding value, returned without numeric scaling as a plain decimal string with redundant trailing zeros removed; returns "0" when the snapshot or value is missing. |
apy | String | Annualized yield in percent; e.g. "8.25" means 8.25%. |
nav | String | Current unit NAV, returned as a plain decimal string with insignificant trailing zeros removed. |
currentShareHolders | String | Current number of share holder addresses. |
shareTokenTotalSupply | String | Current share token total supply; for Standard Vaults it is already converted to the Share Token precision. |
transactionConfigInfo fields:
| Field | Type | Description |
|---|---|---|
flexibleSubAndRedeem | Boolean | Whether flexible subscription and redemption is supported. When the value is true, all three windows return null, and both depositAvailable and redeemAvailable are true. |
cutOffTime | String | Settlement time. |
depositToken | Object | Subscription and redemption token name, address, and decimals; returns null only when all three fields are null. |
subscriptionWindow | Object | Subscription window; null when flexible subscription/redemption applies or there is no data. |
redemptionWindow | Object | Redemption window; null when flexible subscription/redemption applies or there is no data. |
lockWindow | Object | Product lock window; null when flexible subscription/redemption applies or there is no data. |
limits | Object | Subscription/redemption and overall Vault limits. |
settlement | Object | Subscription/redemption settlement configuration. |
feeRates | Object | Vault fee rate configuration. |
depositAvailable | Boolean | Whether subscription is currently allowed. For a non-flexible Standard Vault it is computed from whether the current time falls within the subscription window; returns null when the window or either boundary is missing. |
redeemAvailable | Boolean | Whether redemption is currently allowed. For a non-flexible Standard Vault it is computed from whether the current time falls within the redemption window; returns null when the window or either boundary is missing. |
transactionConfigInfo.depositToken fields:
| Field | Type | Description |
|---|---|---|
tokenName | String | Configured subscription and redemption token name; null when missing. |
address | String | Subscription and redemption token contract address; null when no matching data exists. |
decimals | String | Subscription and redemption token decimals; null when no matching data exists. |
Common fields of subscriptionWindow, redemptionWindow, and lockWindow:
| Field | Type | Description |
|---|---|---|
startDate | String | Window start time in the format yyyy-MM-dd'T'HH:mm:ss with no time-zone offset. |
endDate | String | Window end time in the format yyyy-MM-dd'T'HH:mm:ss with no time-zone offset. |
periodDays | String | Window duration in days, returned as a string. |
transactionConfigInfo.limits fields:
| Field | Type | Description |
|---|---|---|
deposit | Object | Per-order subscription amount limits. |
deposit.minAmount | String | Minimum subscription amount per order. USD |
deposit.maxAmount | String | Maximum subscription amount per order. USD |
redemption | Object | Per-order redemption limits. |
redemption.minShares | String | Minimum redemption share quantity per order. Standard Vaults currently return "0" to indicate no limit. share |
redemption.maxShares | String | Maximum redemption share quantity per order. Standard Vaults currently return "0" to indicate no limit. share |
redemption.minAssets | String | Minimum redemption asset quantity per order. Standard Vaults currently return "0" to indicate no limit. share |
vault | Object | Overall Vault limits. |
vault.maxCap | String | Maximum share supply of the Vault; not a fixed value. |
vault.maxTvl | String | Maximum TVL of the Vault. Standard Vaults currently return "0" to indicate no limit. USD |
Standard Vault
"0"special semantics: Currently the Standard Metadata fieldsredemption.minShares,redemption.maxShares,redemption.minAssets, andvault.maxTvlalways return"0". In these four fields,"0"explicitly means no limit, not a zero quota, and does not indicate that subscription or redemption is forbidden. This rule applies only to these four fixed Standard fields; a"0"in any other field must not be inferred to mean no limit.
transactionConfigInfo.settlement fields:
| Field | Type | Description |
|---|---|---|
settleType | String | Settlement type: "0" means synchronous, "1" means asynchronous. |
depositSettlement | String | Subscription settlement cycle, returned as a numeric string such as "0", "1"; no T+ prefix is added. |
redemptionSettlement | String | Redemption settlement cycle, returned as a numeric string such as "0", "1"; no T+ prefix is added. |
transactionConfigInfo.feeRates fields:
| Field | Type | Description |
|---|---|---|
depositFeeRate | String | User subscription fee rate, in percent. |
withdrawalFeeRate | String | User withdrawal fee rate, in percent. |
performanceFeeRate | String | Vault performance fee rate, in percent. |
managementFeeRate | String | Vault management fee rate, in percent. |
highWaterMark | String | Hurdle benchmark value, returned as a numeric string without unit conversion; null when not configured. |
assetConfig fields:
| Field | Type | Description |
|---|---|---|
shareToken | Object | Static information of the share token. |
underlyingAssets | Array | Underlying asset list; element fields are listed in the table below. |
assetConfig.shareToken fields:
| Field | Type | Description |
|---|---|---|
address | String | Share token contract address. |
addressAtBlock | String | Share token deployment block height, returned as a string. |
decimals | String | Share token decimals, returned as a string. |
symbol | String | Share token symbol. |
name | String | Share token name. |
assetConfig.underlyingAssets[] fields:
| Field | Type | Description |
|---|---|---|
targetVaultAddress | String | Target Vault address associated with the underlying asset. |
vaultToken | Object | Underlying asset token information. |
vaultToken.address | String | Underlying asset token contract address. |
vaultToken.name | String | Underlying asset token name. |
vaultToken.symbol | String | Underlying asset token symbol. |
vaultToken.decimals | String | Underlying asset token decimals, returned as a string. |
adapter | Object | Underlying asset Adapter information. |
adapter.id | String | Adapter identifier. |
adapter.type | String | Adapter type. |
percentageBps | String | Initial asset allocation ratio, returned as a string without ratio conversion. |
logoUrl | String | Underlying asset logo URL. |
accessControl fields:
| Field | Type | Description |
|---|---|---|
curatorAddress | String | Curator permission address. |
hyperManagerAddress | String | Hyperliquid Manager address, queried by Curator Vault ID. Returns null when the upstream query succeeds but no address is configured. |
subscriptionWhitelist | Object | Subscription whitelist configuration. |
subscriptionWhitelist.enabled | Boolean | Whether the subscription whitelist restriction is enabled. |
subscriptionWhitelist.contract | Object | Subscription whitelist guard contract deployment information. |
contractConfig fields:
| Field | Type | Description |
|---|---|---|
coreContract | Object | Vault core contract deployment information. |
moduleContracts | Object | Vault module contract deployment information. |
Common fields of coreContract, subscriptionWhitelist.contract, and each module contract:
| Field | Type | Description |
|---|---|---|
address | String | On-chain contract address. |
addressAtBlock | String | Contract deployment block height, returned as a string. |
contractConfig.moduleContracts fields:
For the responsibilities and collaboration model of these contracts, see the Smart Contracts document.
| Field | Type | Description |
|---|---|---|
feeRouterContract | Object | Fee execution and settlement router contract. |
entryFixedBpsFeeContract | Object | Subscription fee contract. |
exitFixedBpsFeeContract | Object | Redemption fee contract. |
timeAccrualFeeContract | Object | Time-accrued management fee contract. |
hwmPerformanceFeeContract | Object | High-water-mark performance fee contract. |
commissionContract | Object | Fee distribution treasury contract. |
navContract | Object | NAV accounting contract. |
acModuleContract | Object | AC asset allocation module contract. |
escrowContract | Object | Asset custody contract. |
adapterRegistryContract | Object | Adapter and asset registry contract. |
assetSummedNavOracleContract | Object | Portfolio asset valuation contract. |
offchainAssetPriceOracleContract | Object | Off-chain asset price oracle contract. |
vaultAccountingLensContract | Object | NAV and fee preview query contract. |
accessManagerContract | Object | Role and administrative permission contract. |
vaultPolicyRouterContract | Object | Business rule router contract. |
lifecycleRuleContract | Object | Subscription and redemption open-window rule contract. |
vaultLimitGuardContract | Object | Trade limit and product size constraint contract. |
jtrsyAdapterContract | Object | JTRSY-style asynchronous vault adapter contract. |
vrpcqAdapterContract | Object | Vault adapter contract with an external withdrawal queue. |
faroSwapAdapterContract | Object | USDC–WPROS swap adapter contract. |
topnodAdapterContract | Object | Asynchronous buy/sell order adapter contract. |
hyperAdapterContract | Object | Hyperliquid cross-chain fund and position mapping adapter contract. |
topnodRouterContract | Object | Order submission and callback forwarding router contract. |
riskConfig fields:
| Field | Type | Description |
|---|---|---|
riskLevel | String | Vault risk level. |
strategyRiskDisclosureText | String | Strategy risk disclosure text. |
riskDisclosure | String | Vault risk disclosure body text. |
prosperInfo fields:
| Field | Type | Description |
|---|---|---|
prosperTokenName | String | Prosper token name identifier. |
reward | String | Reward value as a decimal string, without unit conversion; null when unset. |
validProsper | String | Whether to include the Pharos token: "1" means included, "0" means not included. |
pVaultLogo | String | Prosper Vault logo; null when unset. |
launchpadPerformanceFeeShare | String | Launchpad performance fee as a decimal string, without unit conversion; null when unset. |
9.2 Query a Single Standard Vault Metadata
Purpose
Query the metadata of a single published Standard Vault by its Vault contract address.
Method + Path
GET /api/r25/standard-vault/metadata
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Enum | Description |
|---|---|---|---|---|
vaultAddress | String | Yes | None | Vault contract address; leading and trailing whitespace is trimmed before querying. |
Request example
curl --get 'https://<api-host>/api/r25/standard-vault/metadata' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
data uses the complete layered Metadata structure in Section 9.1. A Standard Vault returns the currently available basic info, dynamic metrics, transaction configuration, asset configuration, access control, contract configuration, risk configuration, and Prosper info; fields that are currently unavailable or not applicable return null. accessControl.hyperManagerAddress comes from the Hyperliquid service; if that query fails, the entire metadata request returns -1010.
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"vaultBasicInfo": {
"vaultName": "Example USDC Yield Vault",
"vaultLogoUrl": "https://static.example.com/vault.png",
"curationStrategyDescription": "Example strategy description",
"strategyDescription": null,
"yieldStrategy": null,
"chain": {
"chainId": "1",
"chainName": "Ethereum"
},
"offline": false,
"deployTime": "2026-07-29T14:43:52"
},
"auditReports": [
{
"reportUrl": "https://example.com/a.png",
"provider": "AName",
"reportType": "SECURITY_AUDIT"
},
{
"reportUrl": "https://example.com/b.png",
"provider": "BName",
"reportType": "SECURITY_AUDIT"
}
],
"vaultMetrics": {
"tvl": "125000000",
"cFunding": "1",
"apy": "8.25",
"nav": "1.025",
"currentShareHolders": "128",
"shareTokenTotalSupply": "125"
},
"transactionConfigInfo": {
"flexibleSubAndRedeem": false,
"cutOffTime": "16:00:00",
"depositToken": {
"tokenName": "USDC",
"address": "0xc879c018db60520f4355c26ed1a6d572cdac1815",
"decimals": "6"
},
"subscriptionWindow": {
"startDate": "2026-08-05T00:00:00",
"endDate": "2026-08-06T00:00:00",
"periodDays": "1"
},
"redemptionWindow": {
"startDate": "2026-08-07T00:00:00",
"endDate": "2026-08-14T00:00:00",
"periodDays": "7"
},
"lockWindow": {
"startDate": "2026-08-06T00:00:00",
"endDate": "2026-08-07T00:00:00",
"periodDays": "1"
},
"limits": {
"deposit": {
"minAmount": "1000000",
"maxAmount": "100000000"
},
"redemption": {
"minShares": "0",
"maxShares": "0",
"minAssets": "0"
},
"vault": {
"maxCap": "125000000",
"maxTvl": "0"
}
},
"settlement": {
"settleType": "1",
"depositSettlement": "0",
"redemptionSettlement": "1"
},
"feeRates": {
"depositFeeRate": "0",
"withdrawalFeeRate": "0.1",
"performanceFeeRate": "20",
"managementFeeRate": "2",
"highWaterMark": null
},
"depositAvailable": true,
"redeemAvailable": false
},
"assetConfig": {
"shareToken": {
"address": "0x2222222222222222222222222222222222222222",
"addressAtBlock": "23456780",
"decimals": "18",
"symbol": "vUSDC",
"name": null
},
"underlyingAssets": [
{
"targetVaultAddress": "0x4444444444444444444444444444444444444444",
"vaultToken": {
"address": "0x3333333333333333333333333333333333333333",
"name": "USD Yield Token",
"symbol": "USDY",
"decimals": "18"
},
"adapter": {
"id": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "erc4626"
},
"percentageBps": "100",
"logoUrl": "https://static.example.com/usdy.png"
}
]
},
"accessControl": {
"curatorAddress": "0x4444444444444444444444444444444444444444",
"hyperManagerAddress": "0x6666666666666666666666666666666666666666",
"subscriptionWhitelist": {
"enabled": true,
"contract": {
"address": "0xb7d5c363f4bb438d484b64d4fba766bb2b9d9238",
"addressAtBlock": "23456780"
}
}
},
"contractConfig": {
"coreContract": {
"address": "0x1111111111111111111111111111111111111111",
"addressAtBlock": "23456780"
},
"moduleContracts": {
"feeRouterContract": {
"address": "0x5555555555555555555555555555555555555555",
"addressAtBlock": "23456780"
},
"entryFixedBpsFeeContract": {
"address": "0x6666666666666666666666666666666666666666",
"addressAtBlock": "23456780"
},
"exitFixedBpsFeeContract": {
"address": "0x7777777777777777777777777777777777777777",
"addressAtBlock": "23456780"
},
"timeAccrualFeeContract": {
"address": "0x8888888888888888888888888888888888888888",
"addressAtBlock": "23456780"
},
"hwmPerformanceFeeContract": {
"address": "0x9999999999999999999999999999999999999999",
"addressAtBlock": "23456780"
},
"commissionContract": {
"address": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"addressAtBlock": "23456780"
},
"navContract": {
"address": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"addressAtBlock": "23456780"
},
"acModuleContract": {
"address": "0x0000000000000000000000000000000000000001",
"addressAtBlock": "23456780"
},
"escrowContract": {
"address": "0x0000000000000000000000000000000000000002",
"addressAtBlock": "23456780"
},
"adapterRegistryContract": {
"address": "0x0000000000000000000000000000000000000003",
"addressAtBlock": "23456780"
},
"assetSummedNavOracleContract": {
"address": "0x0000000000000000000000000000000000000004",
"addressAtBlock": "23456780"
},
"offchainAssetPriceOracleContract": {
"address": "0x0000000000000000000000000000000000000005",
"addressAtBlock": "23456780"
},
"vaultAccountingLensContract": {
"address": "0x0000000000000000000000000000000000000006",
"addressAtBlock": "23456780"
},
"accessManagerContract": {
"address": "0x0000000000000000000000000000000000000007",
"addressAtBlock": "23456780"
},
"vaultPolicyRouterContract": {
"address": "0x0000000000000000000000000000000000000008",
"addressAtBlock": "23456780"
},
"lifecycleRuleContract": {
"address": "0x0000000000000000000000000000000000000009",
"addressAtBlock": "23456780"
},
"vaultLimitGuardContract": {
"address": "0x000000000000000000000000000000000000000a",
"addressAtBlock": "23456780"
},
"jtrsyAdapterContract": {
"address": "0x000000000000000000000000000000000000000b",
"addressAtBlock": "23456780"
},
"vrpcqAdapterContract": {
"address": "0x000000000000000000000000000000000000000c",
"addressAtBlock": "23456780"
},
"faroSwapAdapterContract": {
"address": "0x000000000000000000000000000000000000000d",
"addressAtBlock": "23456780"
},
"topnodAdapterContract": {
"address": "0x000000000000000000000000000000000000000e",
"addressAtBlock": "23456780"
},
"hyperAdapterContract": {
"address": "0x000000000000000000000000000000000000000f",
"addressAtBlock": "23456780"
},
"topnodRouterContract": {
"address": "0x0000000000000000000000000000000000000010",
"addressAtBlock": "23456780"
}
}
},
"riskConfig": {
"riskLevel": "MEDIUM",
"strategyRiskDisclosureText": null,
"riskDisclosure": null
},
"prosperInfo": {
"prosperTokenName": "pUSDY",
"reward": "0.5",
"validProsper": "1",
"pVaultLogo": null,
"launchpadPerformanceFeeShare": null
}
}
}
In the example above, the three
"0"values intransactionConfigInfo.limits.redemptionand the"0"intransactionConfigInfo.limits.vault.maxTvlall mean no limit, not a zero quota. This interpretation applies only to these four fixed Standard fields and must not be extended to other fields whose value is"0".
Specific limits
- A missing
vaultAddressquery parameter returns-1005; a present but blank value returns-1008. - An address outside the caller's accessible Vault set returns
-1008, including an unknown address outside that set. This error does not distinguish a nonexistent address from an inaccessible one. - If the address passes the access check but no metadata is found, the response uses
-1010. EVM address format is not currently validated; partners should still pass a standard address. - Only published and enabled Vaults can be queried.
9.3 Query the Standard Vault List
Purpose
Query the contract addresses and creation times of published Vaults available to the current partner.
Method + Path
GET /api/r25/standard-vault/vaultList
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Enum | Description |
|---|---|---|---|---|
pageNumber | Integer | No | 1 | Page number, must be ≥ 1. |
pageSize | Integer | No | 10 | Page size, in the range 1 to 100. |
Request example
curl 'https://<api-host>/api/r25/standard-vault/vaultList?pageNumber=1&pageSize=10' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
list | Object[] | Vault info in the current page; [] when there is no data. |
list[].vaultAddress | String | Vault contract address. |
list[].createTime | Long | Vault creation time, Unix millisecond timestamp. |
pageNumber | Integer | Current page number. |
pageSize | Integer | Page size. |
hasNext | Boolean | Whether a next page exists. |
The list is returned in a stable order.
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"list": [
{
"vaultAddress": "0x1111111111111111111111111111111111111111",
"createTime": 1785920900000
},
{
"vaultAddress": "0x2222222222222222222222222222222222222222",
"createTime": 1785982530000
}
],
"pageNumber": 1,
"pageSize": 10,
"hasNext": false
}
}
Specific limits
- Only published and enabled Vaults are returned.
- Each element in
listis an object containingvaultAddressandcreateTime. - Request validation fails when
pageNumberis less than1orpageSizeis outside the1–100range.
9.4 Query Vault Events
Purpose
Starting from the given time, query the Vault events integrated by the system in ascending event time order with pagination. The total count is not returned.
Method + Path
GET /api/r25/standard-vault/events
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Format | Description |
|---|---|---|---|---|
eventTime | Long | Yes | Unix milliseconds | Inclusive query start instant; range 0–253402271999999. The server converts it to Asia/Hong_Kong (UTC+8) for comparison with database event_time, preserving milliseconds. |
pageNumber | Integer | No | 1 | Page number, must be ≥ 1. |
pageSize | Integer | No | 10 | Page size, in the range 1 to 100. |
Request example
curl --get 'https://<api-host>/api/r25/standard-vault/events' \
--data-urlencode 'eventTime=1787558400000' \
--data-urlencode 'pageNumber=1' \
--data-urlencode 'pageSize=10' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
list | Object[] | Vault events in the current page; [] when there is no data. |
list[].eventType | String | Vault lifecycle event type: DEPLOYED, GRAY, or OFFICIAL. |
list[].coreVaultAddress | String | Core Vault contract address. |
list[].changeType | String | Change type. |
list[].changeTime | Long | Change time, Unix millisecond timestamp. |
list[].transactionHash | String | Transaction hash of the change. |
list[].blockHeight | Long | Block height of the change. |
list[].vaultStatus | String | Vault status after the change. |
pageNumber | Integer | Current page number. |
pageSize | Integer | Page size. |
hasNext | Boolean | Whether a next page exists. |
list[].eventType and list[].vaultStatus describe different concepts: a GRAY event has vaultStatus=DEPLOYED; an OFFICIAL event has vaultStatus=OFFICIAL.
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"list": [
{
"eventType": "DEPLOYED",
"coreVaultAddress": "0x1111111111111111111111111111111111111111",
"changeType": "FINALIZE_PRODUCT",
"changeTime": 1786588800000,
"transactionHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"blockHeight": 12345678,
"vaultStatus": "DEPLOYED"
}
],
"pageNumber": 1,
"pageSize": 10,
"hasNext": false
}
}
Specific limits
- The list is returned in ascending change-time order in a stable manner; the start time is inclusive.
- Request validation fails when
eventTimeis missing, is not an integer, or is outside0–253402271999999, whenpageNumberis less than1, or whenpageSizeis outside the1–100range. eventTimealways uses Unix milliseconds, regardless of the partner time zone. Do not add a time-zone offset to the timestamp. Seconds are not auto-detected; date strings are no longer accepted. The signing headerX-Timestampstill uses Unix seconds.- Example: database time
2026-08-17 16:38:34.013in UTC+8 corresponds to2026-08-17T08:38:34.013ZandeventTime=1786955914013. - Returns
-1022when the query fails. - The endpoint returns the actual Vault lifecycle type of each event in
eventType. - Nullable fields in a list item return
nullwhen no value is currently available.
9.5 Query Standard Vault NAV History
Purpose
Query the daily NAV history by Vault contract address, optionally filtered by date range.
Method + Path
GET /api/r25/standard-vault/nav/history
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Format | Description |
|---|---|---|---|---|
vaultAddress | String | Yes | Vault contract address | Used to locate the Standard Vault. |
startDate | String | No | yyyy-MM-dd | Start date for the NAV query. |
endDate | String | No | yyyy-MM-dd | End date for the NAV query. |
Request example
curl --get 'https://<api-host>/api/r25/standard-vault/nav/history' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
--data-urlencode 'startDate=2026-08-01' \
--data-urlencode 'endDate=2026-08-07' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
list | Array | Daily NAV records; [] when there is no data. |
list[].date | String | Millisecond timestamp string corresponding to 00:00 UTC of the day. |
list[].nav | Number | Unit NAV of the day, i.e. the base asset quantity per 1 share. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"list": [
{
"date": "1785974400000",
"nav": 1.025
}
]
}
}
Specific limits
- A missing
vaultAddressquery parameter returns-1005with messageform validation err: vaultAddress is required. - A blank
vaultAddressor a caller identity without an associated Curator returns-1008with messagevault not permitted. An address outside the accessible Vault set also returns-1008, with messagevault not permitted: vaultAddress not permitted: <normalized address>. - After Vault permission is confirmed, a failed NAV query or a downstream response that violates the contract returns
-1012with default messagequery nav history failed. If the downstream service explicitly returns a nonblank failure message, the message isquery nav history failed: <downstream message>. - Only
dateandnavare returned.
9.6 Query Standard Vault Current Positions
Purpose
Query current underlying asset positions by Vault contract address. The response includes the asset symbol, contract address, USD price, position weight, logo URL, 24-hour price change percentage, buy/sell quotes, holding quantity, and holding value.
Method + Path
GET /api/r25/standard-vault/positions
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Format | Description |
|---|---|---|---|---|
vaultAddress | String | Yes | None | Vault contract address. EVM address format is not currently validated. |
Request example
curl --get 'https://<api-host>/api/r25/standard-vault/positions' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
data is an array of positions; when there are no positions, it is an empty array [].
| Field | Type | Description |
|---|---|---|
[].symbol | String | Asset symbol. |
[].address | String | Asset contract address. |
[].price | Number | Current price per asset unit in USD. |
[].weight | Number | Current position weight in percent; e.g. 25.5 means 25.5%. |
[].logoUrl | String | Asset logo URL. |
[].priceChange | Number | Price change percentage over the past 24 hours. A positive value indicates an increase and a negative value indicates a decrease; e.g. -0.0060 means -0.0060%. |
[].priceQuote | Number | Buy quote of the asset, in USD. |
[].priceQuoteSell | Number | Sell quote of the asset, in USD. |
[].amount | String | Holding quantity; null when the upstream provides no value. |
[].value | Number | Holding value, in USD. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": [
{
"symbol": "USDC",
"address": "0x3333333333333333333333333333333333333333",
"price": 1.0000,
"weight": 40.0000,
"logoUrl": "https://static.example.com/usdc.png",
"priceChange": -0.0060,
"priceQuote": 1.0001,
"priceQuoteSell": 0.9999,
"amount": "4000000.0000",
"value": 4000000.0000
},
{
"symbol": "USDY",
"address": "0x4444444444444444444444444444444444444444",
"price": 1.0250,
"weight": 60.0000,
"logoUrl": "https://static.example.com/usdy.png",
"priceChange": 0.9300,
"priceQuote": 1.0251,
"priceQuoteSell": 1.0249,
"amount": "5853658.5366",
"value": 6000000.0000
}
]
}
Specific limits
- A missing
vaultAddressquery parameter returns-1005with messageform validation err: vaultAddress is required. - A blank
vaultAddressor a caller identity without an associated Curator returns-1008with messagevault not permitted. An address outside the accessible Vault set also returns-1008, with messagevault not permitted: vaultAddress not permitted: <normalized address>. - After Vault permission is confirmed, a failed positions query or a downstream response that violates the contract returns
-1021with default messagequery positions failed. If the downstream service explicitly returns a nonblank failure message, the message isquery positions failed: <downstream message>. - When
symbol,address,price,weight,logoUrl,priceChange,priceQuote,priceQuoteSell,amount, orvaluehas no value, the corresponding field returnsnull. - The endpoint returns the positions list and does not include total AUM, asset quantity, holding quantity, or holding value.
9.6.1 Query a Hyperliquid Manager Account
Purpose
Query the Hyperliquid Manager account for a Curator Vault contract address. The caller must have access to the published Vault.
Method + Path
GET /api/r25/standard-vault/hyperliquid/account
Request location
Query; no request body.
| Field | Type | Required | Description |
|---|---|---|---|
vaultAddress | String | Yes | Curator Vault contract address; leading/trailing whitespace is removed and matching is case insensitive. |
curl --get 'https://<api-host>/api/r25/standard-vault/hyperliquid/account' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response fields**
| Field | Type | Description |
|---|---|---|
vaultId | Long | Hyperliquid Vault ID; different from the Curator Vault ID resolved from the request. |
managerAddress | String | Manager address. |
agentAddress | String | Agent address. |
portfolioValue | BigDecimal | Current Hyperliquid Perpetuals account equity; it is not the TVL of the entire Vault. |
availableToTrade | BigDecimal | Amount currently available to open positions or trade. |
marginUsed | BigDecimal | Margin currently used. |
unrealizedPnl | BigDecimal | Current unrealized profit or loss. |
positionCount | Integer | Current position count. |
perpsMaintenanceMargin | BigDecimal | Perpetuals maintenance margin. |
unifiedAccountRatio | BigDecimal | Unified account margin usage in percent; 25 means 25%. |
unifiedAccountLeverage | BigDecimal | Unified account leverage multiple. |
totalNtlPos | BigDecimal | Total notional position value. |
totalRawUsd | BigDecimal | Raw USD balance in the Hyperliquid account. |
withdrawable | BigDecimal | Amount currently withdrawable from Hyperliquid. |
totalInflow | BigDecimal | Ledger cumulative amount transferred into Hyperliquid. |
totalOutflow | BigDecimal | Ledger cumulative amount transferred out of Hyperliquid. |
Field notes
portfolioValueis the current equity of the Hyperliquid Perpetuals account. It is not the TVL of the entire Vault.availableToTradeis the amount currently available to open positions or trade.withdrawableis the amount currently withdrawable from the Hyperliquid account.unrealizedPnlis the unrealized profit or loss of current positions.totalInflowandtotalOutfloware cumulative ledger statistics.- Returned monetary fields are denominated in USDC.
positionCountis a count,unifiedAccountRatiois a percentage, andunifiedAccountLeverageis a multiple.totalRawUsdretains the downstream field name.
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"vaultId": 42,
"managerAddress": "0x2222222222222222222222222222222222222222",
"agentAddress": "0x3333333333333333333333333333333333333333",
"portfolioValue": 998.240619,
"availableToTrade": 500,
"marginUsed": 200,
"unrealizedPnl": -1.5,
"positionCount": 2,
"perpsMaintenanceMargin": 20,
"unifiedAccountRatio": 20.04,
"unifiedAccountLeverage": 0.5,
"totalNtlPos": 499.12,
"totalRawUsd": 998.240619,
"withdrawable": 798.240619,
"totalInflow": 1000,
"totalOutflow": 0
}
}
BigDecimal fields are decimal JSON numbers and need no conversion from on-chain base units. Unauthorized Vault access, a blank address, or an unknown address outside the accessible set returns -1008. If the address passes the access check, a missing or duplicate mapping, an invalid mapped ID, or a failed or empty downstream response returns -1026. This route depends on downstream GET /api/internal/vault/account?curatorVaultId=...; until it is deployed, requests that pass the access check and call the downstream service return -1026.
9.7 Standard Vault Preview
Purpose
Perform ERC4626 read-only previews via the Lens contract to convert between asset quantity and share quantity without sending on-chain transactions.
Method + Path
| Method | Path | Input | Contract preview result |
|---|---|---|---|
| GET | /api/r25/standard-vault/preview/mint | shares | assets required to deposit |
| GET | /api/r25/standard-vault/preview/redeem | shares | assets redeemable |
| GET | /api/r25/standard-vault/preview/deposit | assets | shares mintable |
| GET | /api/r25/standard-vault/preview/withdraw | assets | shares to burn |
Request location
Query; no request body.
Request fields
| Field | Type | Required | Applicable endpoints | Description |
|---|---|---|---|---|
vaultAddress | String | Yes | All | 0x or 0X prefix plus 40 hexadecimal characters. |
shares | String | Yes | mint, redeem | On-chain minimum-unit quantity of shares, as a uint256 decimal string; only 0 or a non-negative integer not starting with 0 is allowed. |
assets | String | Yes | deposit, withdraw | On-chain minimum-unit quantity of the underlying asset, as a uint256 decimal string; only 0 or a non-negative integer not starting with 0 is allowed. |
Request example
curl --get 'https://<api-host>/api/r25/standard-vault/preview/mint' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
--data-urlencode 'shares=1000000000000000000' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
curl --get 'https://<api-host>/api/r25/standard-vault/preview/deposit' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
--data-urlencode 'assets=1000000' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
vaultAddress | String | Echoes the Vault contract address from the request. |
shares | String | On-chain minimum-unit quantity of shares; echoed from the input in mint/redeem, and the contract result in deposit/withdraw. |
assets | String | On-chain minimum-unit quantity of the underlying asset; echoed from the input in deposit/withdraw, and the contract result in mint/redeem. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"vaultAddress": "0x1111111111111111111111111111111111111111",
"shares": "1000000000000000000",
"assets": "1025000"
}
}
Specific limits
shares/assetsmust not exceed2^256 - 1; an invalid format or value range returns-1005.- Returns
-1020when the preview calculation fails.
9.10 Query the Vault Asset Catalog
GET /api/r25/assets/list
Query parameters:
| Parameter | Required | Description |
|---|---|---|
exchange | No | Asset source; accepted filter values are listed below. Omit for no source filter; results may include HYPER rows. |
net | No | Network or chain type, such as ETH, PHAROS, or SOLANA; omit for no limit. |
symbol | No | Asset code, such as GLD or ETH; omit for no limit. |
tokenAddress | No | On-chain token address; omit for no limit. |
pageNumber | No | Defaults to 1; must be at least 1, otherwise business code "-1005" is returned. |
pageSize | No | Defaults to 10; must be at least 1, otherwise business code "-1005" is returned. |
Accepted exchange values:
| Value | Meaning |
|---|---|
TOPNOD | TopNode assets. |
JTRSY | JTRSY assets. |
USDC | USDC quote currency. |
Other exchange values return parameter validation code "-1005"; use the separate endpoint for Hyperliquid. Success returns HTTP 200 and business code "200". Fields of data:
| Field | Type | Description |
|---|---|---|
pageNum | int | Current page number. |
pageSize | int | Number of items per page. |
size | int | Number of items on the current page. |
total | long | Total matching records. |
pages | int | Total pages. |
list | List | Asset list. |
Fields of list[]:
| Field | Type | Description |
|---|---|---|
id | Long | Asset ID, the primary key of the asset table. |
exchange | String | Asset source, mapped from source_type, such as TOPNOD, HYPER, JTRSY, or USDC. |
tokenAddress | String | On-chain token address, mapped from token_address. |
net | String | Network or chain type, mapped from chain_type. |
symbol | String | Asset code, mapped from asset_code. |
assetName | String | Asset name. |
decimals | Integer | Token precision. |
isActive | Integer | Whether enabled: 1 yes, 0 no. |
A failed query or invalid response shape returns business code "-1029".
Example Vault asset catalog data:
{
"pageNum": 1,
"pageSize": 10,
"size": 1,
"total": 1,
"pages": 1,
"list": [{"id": 123, "exchange": "TOPNOD", "tokenAddress": "0x567890abcdef1234567890abcdef123456789012", "net": "ETH", "symbol": "GLD", "assetName": "SPDR Gold Shares", "decimals": 18, "isActive": 1}]
}
9.11 Query the Hyperliquid Asset List
GET /api/r25/hyperliquid/assets/list
Query parameters:
| Parameter | Required | Description |
|---|---|---|
symbol | No | Case-insensitive substring match on asset name, such as ETH, US500, or MKTS:US500; blank means no filter. |
productType | No | ALL, CRYPTO, or TRADFI; ALL or blank means no product type limit. |
category | No | Tradfi category: STOCKS, INDICES, COMMODITIES, FX, or PRE_IPO; ALL means no category limit. Usually omitted for CRYPTO. |
dex | No | DEX deployer, such as km, mkts, or xyz; ALL means no DEX limit. |
page | No | Defaults to 1; must be at least 1, otherwise business code "-1005" is returned. |
pageSize | No | Defaults to 20; must be between 1 and 200, otherwise business code "-1005" is returned. |
The downstream service filters by symbol, then productType / category / dex, and finally paginates. total counts all matching assets after filtering. This endpoint uses the existing public response envelope (code, message, timestamp, data; success is omitted). Its data retains the Hyperliquid shape:
| Field | Type | Description |
|---|---|---|
assets | Array | Assets on the current page. |
page | Integer | Page number actually used. |
pageSize | Integer | Page size actually used. |
total | Long | Total matching assets after all filters. |
hasNext | Boolean | Whether another page exists. |
symbol | String | Symbol condition used for this request; may be null when omitted. |
filters | Array | Available product types and Tradfi category options. |
marginTables | Array | Original margin tables; each entry is a two-element array [marginTableId, tableBody]. |
Fields of assets[]:
| Field | Type | Description |
|---|---|---|
assetId | Integer | Asset identifier. |
name | String | Standard asset name, such as ETH or MKTS:US500. |
symbol | String | Standard symbol used for orders. |
displayName | String | Display name. |
internalName | String | Internal asset name. |
dex | String | DEX deployer, such as main, xyz, or mkts. |
marketType | String | Market type, currently mainly PERP. |
productType | String | CRYPTO or TRADFI. |
category | String | Tradfi category; usually empty for Crypto. |
quoteAsset | String | Quote asset, such as USDC. |
szDecimals | Integer | Order size precision. |
maxLeverage | Integer | Base maximum leverage. |
onlyIsolated | Boolean | Whether only isolated margin is supported; may be null. |
marginTableId | Integer | Matching margin table ID; may be null. |
A failed query or invalid response shape returns business code "-1029".
Example Hyperliquid data:
{
"page": 1,
"pageSize": 20,
"total": 1,
"hasNext": false,
"symbol": "US500",
"assets": [{"assetId": 190000, "name": "MKTS:US500", "symbol": "MKTS:US500", "displayName": "MKTS:US500-USDC", "internalName": "mkts:MKTS:US500", "dex": "mkts", "marketType": "PERP", "productType": "TRADFI", "category": "STOCKS", "quoteAsset": "USDC", "szDecimals": 3, "maxLeverage": 25, "onlyIsolated": null, "marginTableId": 25}],
"filters": [{"productType": "TRADFI", "label": "Tradfi", "categories": [{"category": "STOCKS", "label": "Stocks"}]}],
"marginTables": [[25, {"description": "tiered 25x", "marginTiers": [{"lowerBound": "0.0", "maxLeverage": 25}]}]]
}
9.12 Configure Vault Assets
POST /api/r25/assets/configuration
Requires Content-Type: application/json and accepts no Query parameters. Example body:
{
"assets": [
{ "symbol": "USDC", "chainType": "Pharos" },
{ "symbol": "ETH", "chainType": "ETH" }
],
"vaultAddress": "0x0000000000000000000000000000000000000001",
"operation": "ADD"
}
assets is an array of assets to configure (up to 100 entries; entries are trimmed and deduplicated by symbol+chainType), and different entries may belong to different chains. Each entry's symbol, together with its chainType, must identify exactly one asset; if any entry cannot, the whole request fails with -1027. operation accepts only uppercase ADD or REMOVE; all assets are applied in one batch. The caller must have permission to operate the specified Vault. On success, this endpoint returns HTTP 200, business code "200", and data: true. A failed configuration returns -1027; when the outcome cannot be confirmed, it returns -1028. Check the actual configuration state before retrying.
10. Rebate Channel Distribution Endpoints
10.1 Query Channel Cumulative Commission
Purpose
Query the current distribution rules of a given channel and Vault, and the cumulative commission aggregated by Refcode.
Method + Path
GET /api/r25/channel-distribution/commission
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Enum | Description |
|---|---|---|---|---|
channelCode | String | No | None | Optional channel stable code; must not be blank-only when provided; leading and trailing whitespace is trimmed before use. |
refcode | String | No | None | Refcode; must not be blank-only when provided; leading and trailing whitespace is trimmed before use. |
vaultAddress | String | No | 0x + 40 hexadecimal characters | Optional Core Vault contract address; must conform to the EVM address format when provided, and lowercased before querying. |
Request example
curl --get 'https://<api-host>/api/r25/channel-distribution/commission' \
--data-urlencode 'channelCode=CHANNEL_EXAMPLE' \
--data-urlencode 'refcode=REF_EXAMPLE' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
dataAsOf | String | Data statistic time point, ISO 8601 UTC. |
vault.chainId | Long | Chain ID. |
vault.vaultAddress | String | Core Vault contract address. |
vault.name | String | Vault name. |
vault.symbol | String | Vault share token symbol. |
vault.assetAddress | String | Base asset address. |
vault.assetDecimals | Integer | Base asset decimals. |
channel.channelCode | String | Channel code. |
channel.name | String | Channel name. |
channel.status | String | Channel status. |
channel.payoutWallet.address | String | Channel commission payout wallet address. |
channel.payoutWallet.chainCode | String | Payout wallet chain identifier. |
items | Array | Refcode-dimension distribution and commission results. |
items[].refcode.code | String | Refcode. |
items[].refcode.label | String | Refcode label. |
items[].refcode.status | String | Refcode status. |
items[].distribution.enabled | Boolean | Whether distribution is currently enabled. |
items[].distribution.status | String | Distribution status. |
items[].distribution.effectiveRates.managementRate | Number | Current management fee rebate percentage. |
items[].distribution.effectiveRates.performanceRate | Number | Current performance fee rebate percentage. |
items[].distribution.rateSource | String | Source of the currently effective rates. |
items[].distribution.effectivePeriod.startTime | String | Start time of the current rule. |
items[].distribution.effectivePeriod.endTime | String | End time of the current rule; null when there is none. |
items[].commission.attributedInflow | Object | Cumulative valid attributed inflow, using the AssetAmount structure. |
items[].commission.attributionRate | Number | Attribution ratio on the Share-Seconds basis. |
items[].commission.attributionRateBasis | String | Attribution ratio calculation basis. |
items[].commission.timeWeightedTvl | Object | Time-weighted TVL, includes valuation reliability status. |
items[].commission.components | Array | Commission details split by fee, asset, and status. |
AssetAmount, TimeWeightedTvl, and CommissionComponent:
| Structure | Field | Type | Description |
|---|---|---|---|
| AssetAmount | assetAddress | String | Asset address. |
| AssetAmount | assetDecimals | Integer | Asset decimals. |
| AssetAmount | amount | String | Raw on-chain asset quantity. |
| TimeWeightedTvl | assetAddress | String | Asset address. |
| TimeWeightedTvl | assetDecimals | Integer | Asset decimals. |
| TimeWeightedTvl | amount | String | Raw on-chain asset quantity. |
| TimeWeightedTvl | valuationStatus | String | Valuation reliability status. |
| CommissionComponent | feeType | String | Fee type. |
| CommissionComponent | assetType | String | Commission asset type. |
| CommissionComponent | assetAddress | String | Commission asset address. |
| CommissionComponent | assetDecimals | Integer | Commission asset decimals. |
| CommissionComponent | amount | String | Raw on-chain commission asset quantity. |
| CommissionComponent | status | String | Commission ledger status. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"dataAsOf": "2026-08-13T08:00:00Z",
"vault": {
"chainId": 1,
"vaultAddress": "0x1111111111111111111111111111111111111111",
"name": "Example Vault",
"symbol": "vUSDC",
"assetAddress": "0x3333333333333333333333333333333333333333",
"assetDecimals": 6
},
"channel": {
"channelCode": "CHANNEL_EXAMPLE",
"name": "Example Channel",
"status": "ACTIVE",
"payoutWallet": {
"address": "0x4444444444444444444444444444444444444444",
"chainCode": "ETH"
}
},
"items": [
{
"refcode": {
"code": "REF_EXAMPLE",
"label": "Example Refcode",
"status": "ACTIVE"
},
"distribution": {
"enabled": true,
"status": "ACTIVE",
"effectiveRates": {
"managementRate": 20.0,
"performanceRate": 15.0
},
"rateSource": "CHANNEL",
"effectivePeriod": {
"startTime": "2026-08-01T00:00:00Z"
}
},
"commission": {
"attributedInflow": {
"assetAddress": "0x3333333333333333333333333333333333333333",
"assetDecimals": 6,
"amount": "2500000000"
},
"attributionRate": 12.5,
"attributionRateBasis": "SHARE_SECONDS",
"timeWeightedTvl": {
"assetAddress": "0x3333333333333333333333333333333333333333",
"assetDecimals": 6,
"amount": "1800000000",
"valuationStatus": "AVAILABLE"
},
"components": [
{
"feeType": "MANAGEMENT_FEE",
"assetType": "UNDERLYING",
"assetAddress": "0x3333333333333333333333333333333333333333",
"assetDecimals": 6,
"amount": "12000000",
"status": "ACCRUED"
}
]
}
}
]
}
}
Specific limits
- A partner can only query channels authorized to it by the platform.
- Amount strings are raw on-chain asset quantities; partners should display them together with the corresponding
assetDecimals. - Rate values are percentages, e.g.
20.0means 20%, not 0.2. - The response does not include recalculated commission, cross-asset totals, or USD valuation.
10.2 Query Channel Attribution Flows
Purpose
Paginated query of attributed inflow and outflow records for a given channel and Vault.
Method + Path
GET /api/r25/channel-distribution/transactions
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Enum | Description |
|---|---|---|---|---|
channelCode | String | Yes | None | Channel stable code; leading and trailing whitespace is trimmed before use. |
refcode | String | No | None | Refcode; must not be blank-only when provided. |
vaultAddress | String | Yes | 0x + 40 hexadecimal characters | Core Vault contract address; lowercased before querying. |
transactionType | String | No | deposit / withdraw | Case-sensitive. |
pageNumber | Integer | No | Default 1; min 1 | The request parameter name is pageNumber. |
pageSize | Integer | No | Default 20; range 1..100 | Page size. |
Request example
curl --get 'https://<api-host>/api/r25/channel-distribution/transactions' \
--data-urlencode 'channelCode=CHANNEL_EXAMPLE' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111' \
--data-urlencode 'transactionType=deposit' \
--data-urlencode 'pageNumber=1' \
--data-urlencode 'pageSize=20' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
pageNum | Integer | Current page number. Note that the response field name differs from the request's pageNumber. |
pageSize | Integer | Current page size. |
hasNext | Boolean | Whether a next page exists. |
items | Array | Current page of flows. |
items[].eventId | String | Unique identifier of the rebate-chain event. |
items[].chainId | Long | Chain ID. |
items[].txHash | String | Transaction hash. |
items[].blockNumber | Long | Block height. |
items[].transactionIndex | Integer | Transaction index within the block. |
items[].logIndex | Integer | Log index of the transaction. |
items[].time | String | On-chain event time. |
items[].type | String | deposit or withdraw. |
items[].refcode | String | Attributed refcode. |
items[].wallet | String | Masked wallet address, usually keeping only the first 6 and the last 4 characters. |
items[].amount.assetAddress | String | Base asset address. |
items[].amount.assetDecimals | Integer | Base asset decimals. |
items[].amount.amount | String | Raw on-chain base asset quantity. |
items[].shares | String | Corresponding raw share quantity. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"pageNum": 1,
"pageSize": 20,
"hasNext": false,
"items": [
{
"eventId": "evt_example_001",
"chainId": 1,
"txHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"blockNumber": 23456789,
"transactionIndex": 12,
"logIndex": 3,
"time": "2026-08-13T08:00:00Z",
"type": "deposit",
"refcode": "REF_EXAMPLE",
"wallet": "0x1111...1111",
"amount": {
"assetAddress": "0x3333333333333333333333333333333333333333",
"assetDecimals": 6,
"amount": "1000000"
},
"shares": "975609756097560975"
}
]
}
}
Specific limits
- A partner can only query channels authorized to it by the platform.
- The response does not output the total count; whether a next page exists is indicated only by
hasNext. walletis masked and does not return the full holder address; an abnormally short value returns****.
10.3 Batch Query Channel Merkle Proofs
Purpose
Paginated query of the claimable amount and Merkle proofs of a given channel and multiple Vaults, scoped by the caller's Curator permission.
Method + Path
GET /api/r25/channel-distribution/merkle-proofs/batch
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Restriction | Description |
|---|---|---|---|---|
channelAddress | String | Yes | 0x + 40 hexadecimal characters | Channel login address; lowercased before querying. |
vaultAddress | String[] | Yes | Each item is 0x + 40 hexadecimal characters | Vault on-chain addresses; multiple values are comma-separated, and the same Query Key must not be repeated. The service converts them to the Vault IDs required by Rebate. |
pageNumber | Integer | No | Default 1; min 1 | Current page number. |
pageSize | Integer | No | Default 20; range 1..100 | Page size. |
Request example
curl --get 'https://<api-host>/api/r25/channel-distribution/merkle-proofs/batch' \
--data-urlencode 'channelAddress=0x9b82166ff1a8ad0194d06a08f1738ffb0a367ca5' \
--data-urlencode 'vaultAddress=0x1111111111111111111111111111111111111111,0x2222222222222222222222222222222222222222' \
--data-urlencode 'pageNumber=1' \
--data-urlencode 'pageSize=20' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
authorizedVaultIds | Long[] | Vault external IDs that the current Curator is authorized to query. |
pageSize | Integer | Current page size. |
pageNumber | Integer | Current page number. |
hasNext | Boolean | Whether a next page exists. |
proofs | Array | Merkle Proof results in the current page. |
proofs[].vaultId | Long | Vault external ID. |
proofs[].address | String | Actual channel rebate receiving address used to generate the proof. |
proofs[].amount | String | Claimable amount in minimum-unit integer. |
proofs[].proof | String[] | Merkle Proof hash path; can be an empty array when the leaf is the root. |
proofs[].merkleRoot | String | Merkle root of the latest ALLOCATED batch. |
proofs[].claimAddress | String | Corresponding Vault project_fee_treasury contract address. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1788182198245,
"data": {
"authorizedVaultIds": [900464],
"pageSize": 20,
"pageNumber": 1,
"hasNext": false,
"proofs": [
{
"vaultId": 900464,
"address": "0x9b82166ff1a8ad0194d06a08f1738ffb0a367ca5",
"amount": "759505619177563",
"proof": [
"8dfcb39fc220c662db9bd81034f6676e36f8445eb1aa6ba308b04e942973b08c"
],
"merkleRoot": "1b08f4b461226f63683fabe885d9a986db1b35cb869b00e4126275b010ca4065",
"claimAddress": "0x146a8d35e64d3919994749561a33dc8b96e5862d"
}
]
}
}
Specific limits
- The Curator address comes from the verified calling identity and cannot be specified or replaced via request parameters.
- The response does not include
currentCountortotalCount; usehasNextto determine whether another page is available. amountis a minimum-unit on-chain integer string and must not be parsed as a floating-point number.
11. Transaction Records Endpoint
11.1 Query Transaction Records by Conditions
Purpose
Paginated query of the Vault on-chain transaction event records currently integrated, filterable by business owner wallet address, Vault contract address, transaction type, status, and async request ID.
Method + Path
GET /api/r25/standard-vault/transaction/records
Request location
Query; no request body.
Request fields
| Field | Type | Required | Default/Enum | Description |
|---|---|---|---|---|
address | String | No | 0x + 40 hexadecimal characters | Business owner wallet address; leading and trailing whitespace is trimmed and lowercased before querying. |
vaultAddress | String | No | 0x + 40 hexadecimal characters | Vault contract address; leading and trailing whitespace is trimmed and lowercased before querying. |
recordType | String | No | DEPOSIT / REDEEM | Case-insensitive; an empty string means no filter; other values fail validation. |
status | String | No | PENDING / CLAIMED / CANCELLED | Case-insensitive; an empty string means no filter; other values fail validation. |
requestId | String | No | None | Async request ID; a blank value is treated as no filter. |
pageNumber | Integer | No | Default 1; min 1 | Page number. |
pageSize | Integer | No | Default 100; range 1..100 | Page size. |
Request example
curl --get 'https://<api-host>/api/r25/standard-vault/transaction/records' \
--data-urlencode 'address=0x1111111111111111111111111111111111111111' \
--data-urlencode 'vaultAddress=0x2222222222222222222222222222222222222222' \
--data-urlencode 'recordType=deposit' \
--data-urlencode 'status=claimed' \
--data-urlencode 'pageNumber=1' \
--data-urlencode 'pageSize=100' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>'
data** response field description**
| Field | Type | Description |
|---|---|---|
list | Array | Transaction records in the current page. |
pageNumber | Integer | Current page number. |
pageSize | Integer | Current page size. |
total | Long | Total number of matching records. |
hasNext | Boolean | Whether a next page exists. |
list[].requestTxHash | String | Request transaction hash. |
list[].requestType | String | DEPOSIT or REDEEM. |
list[].vaultAddress | String | Vault contract address. |
list[].status | String | PENDING, CLAIMED, or CANCELLED. |
list[].assets | String | Asset quantity, raw on-chain un-scaled integer string. |
list[].shares | String | Share quantity, raw on-chain un-scaled integer string. |
list[].chainId | Long | Chain ID. |
list[].requestBlockNumber | Long | Block height of the request transaction. |
list[].requestBlockTime | Long | Request transaction block time, epoch seconds. |
list[].requestId | String | Async request ID; null for synchronous transactions. |
list[].settleTxHash | String | Settlement transaction hash; null when not settled. |
list[].settleBlockTime | Long | Settlement transaction block time, epoch seconds; null when not settled. |
list[].walletAddress | String | Business owner user wallet address. |
Response example
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800123,
"data": {
"list": [
{
"requestTxHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"requestType": "DEPOSIT",
"vaultAddress": "0x2222222222222222222222222222222222222222",
"status": "CLAIMED",
"assets": "1000000",
"shares": "975609756097560975",
"chainId": 1,
"requestBlockNumber": 23456789,
"requestBlockTime": 1786588700,
"requestId": null,
"settleTxHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"settleBlockTime": 1786588700,
"walletAddress": "0x1111111111111111111111111111111111111111"
}
],
"pageNumber": 1,
"pageSize": 100,
"total": 1,
"hasNext": false
}
}
Specific limits
assetsandsharesare raw on-chain un-scaled integer strings; when the client needs to compute, they should be parsed with an arbitrary-precision integer type.- Results are returned in descending order of request block height and transaction index within the block; records at the same position retain a deterministic order.
recordTypeandstatusallow only the current business enums listed in the table; any other non-empty value returns-1005.- Both
addressandvaultAddressare optional. When no business filter is provided, all available records are returned according to the pagination parameters.
12. Trading REST Write Endpoints
12.1 Common Request Envelope and Constraints
Trading REST provides order creation, order cancellation, and position closing. None of the three endpoints accept query parameters; their request bodies use the same envelope:
{
"ts": 1786588800123,
"exchange": "HYPERLIQUID",
"data": {
"vaultAddress": "0x2222222222222222222222222222222222222222"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
ts | Long | Yes | Request generation time, Unix milliseconds. A request older than 10 seconds before the server's current time returns INVALID_REQUEST; regenerate it on every request or retry. Do not send a future time. |
exchange | String | Yes | Use uppercase HYPERLIQUID or HABITTRADE; values are case-sensitive. |
data | Object | Yes | The business parameter object for the current operation. The request fails when it is missing or is not a JSON Object. |
data.vaultAddress | String | Yes | Vault contract address. Leading and trailing whitespace is removed and the value is converted to lowercase. The Vault must be within the operating permissions of the current X-Client-Id. |
In addition to the body ts, the request must still carry X-Client-Id, X-Timestamp, and X-Signature from Section 3. The signature digest must be computed from the final sent raw bytes of the complete envelope, not from data only.
Decimal values such as quantity, price, and leverage should be JSON strings to avoid floating-point precision loss. maxSlippageBps may be a JSON integer or an integer string; 50 means 50 bps, i.e. 0.5%.
Trading REST currently does not accept clientOrderId and provides no business-level idempotency key. Authentication replay protection can only reject requests with completely identical signing material within the time window; resending with a changed ts or body is not the same replay. Therefore, when you receive UPSTREAM_RESULT_UNKNOWN, a network timeout, or the client gets no response, you must not directly repeat the order or close; first confirm the previous result via the order/position query capability.
12.2 Create Order
Method + Path
POST /api/r25/trade/order/create
data** request fields**
| Field | Type | Hyperliquid | HabitTrade | Description |
|---|---|---|---|---|
vaultAddress | String | Required | Required | Vault contract address; the current caller must be authorized to operate it. |
symbol | String | Required | Either symbol or tokenAddress | Trading asset identifier, used as provided. For HabitTrade, either symbol or tokenAddress is required. |
side | String | Required | Required | BUY or SELL, case-insensitive. |
orderType | String | Required | Required | LIMIT or MARKET, case-insensitive. |
quantity | String | Required | Required | Order quantity decimal string; must conform to the valid quantity precision of the current exchange. |
price | String | Required for LIMIT | Should be provided for LIMIT | Limit price. Hyperliquid rejects a request when this field is missing; valid HabitTrade values follow its trading rules. |
maxSlippageBps | Integer / String | Required for MARKET | Required | Maximum slippage in BPS. Hyperliquid MARKET allows 1..1000; HabitTrade uses this value as both maximum loss and maximum slippage, and its valid range follows HabitTrade rules. |
leverage | String | Required | Not used | Leverage multiplier represented as a decimal string. |
timeInForce | String | Optional | Not used | Hyperliquid time-in-force value; supported values must be agreed with the exchange. |
reduceOnly | Boolean | Optional, default false | Not used | Reduce-only flag. |
tokenAddress | String | Not used | Either symbol or tokenAddress | HabitTrade asset contract address; either symbol or tokenAddress is required, and INVALID_REQUEST is returned when both are missing. |
Request example: Hyperliquid market order
curl 'https://<api-host>/api/r25/trade/order/create' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds-or-milliseconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"ts":1786588800123,"exchange":"HYPERLIQUID","data":{"vaultAddress":"0x2222222222222222222222222222222222222222","symbol":"BTC","side":"BUY","orderType":"MARKET","quantity":"0.01","maxSlippageBps":50,"leverage":"5","reduceOnly":false}}'
The body in --data-raw is only a structural example; the actual call must use the current ts and sign on the completely identical raw body bytes.
Success response: Hyperliquid
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800456,
"data": {
"orderId": "HYPERLIQUID:123456789",
"exchangeOrderId": "123456789",
"status": "PENDING",
"acceptedAt": 1786588800400,
"encodedData": null
}
}
Request example: HabitTrade market order
curl 'https://<api-host>/api/r25/trade/order/create' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds-or-milliseconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"ts":1787751481326,"exchange":"HABITTRADE","data":{"vaultAddress":"0xd12041f181cbd0ec66b459de1f5ce219254c62df","tokenAddress":"0x804688f293c15a5454586217a69f1cb36c20e15b","symbol":"SPCHs","side":"BUY","orderType":"MARKET","quantity":"1","maxSlippageBps":"3000"}}'
The body in --data-raw is only a structural example; the actual call must use the current ts and sign on the completely identical raw body bytes.
Success response: HabitTrade
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1787751486434,
"data": {
"orderId": "HABITTRADE:62f917df0a7f483e9783d8fd4b7b8115",
"exchangeOrderId": "62f917df0a7f483e9783d8fd4b7b8115",
"status": "BUILT",
"acceptedAt": 1787751486433,
"encodedData": "0xfca9bd9e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002079221cb9c824c72098e5c5b4f56869f24f3ff75138f3559d60feecacdbe3362d0000000000000000000000000000000000000000000000000000000000000009000000000000000000000000c879c018db60520f4355c26ed1a6d572cdac18150000000000000000000000000000000000000000000000000000000000b6e42b000000000000000000000000804688f293c15a5454586217a69f1cb36c20e15b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000006a8ef345000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000bb80000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
}
}
| Field | Type | Description |
|---|---|---|
orderId | String | Platform-normalized order ID, usually <exchange>:<exchangeOrderId>; may be null when no exchange order ID is available. |
exchangeOrderId | String | Exchange order ID; may be null when no value is available. |
status | String | PENDING when Hyperliquid successfully accepts; BUILT when HabitTrade successfully builds the transaction to be signed. |
acceptedAt | Long | Acceptance time in Unix milliseconds. Hyperliquid uses the exchange-provided time when available, otherwise the API response time; HabitTrade uses the API response time. |
encodedData | String | ABI-encoded data to be signed returned by HabitTrade; Hyperliquid returns null. |
HabitTrade's BUILT only means the transaction parameters have been built; the partner still needs to complete signing and on-chain submission per the mutual agreement, and must not treat it as on-chain settlement.
12.3 Cancel Order
Method + Path
POST /api/r25/trade/order/cancel
Currently only Hyperliquid supports cancellation; exchange=HABITTRADE always returns FEATURE_UNSUPPORTED.
data** request fields**
| Field | Type | Required | Description |
|---|---|---|---|
vaultAddress | String | Yes | Vault contract address; the current caller must be authorized to operate it. |
exchangeOrderId | String | Yes | Hyperliquid order ID, must be parseable as a Long. When passing the platform orderId, strip the HYPERLIQUID: prefix first. |
symbol | String | Yes | Trading asset identifier, used as provided. |
Request example
curl 'https://<api-host>/api/r25/trade/order/cancel' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds-or-milliseconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"ts":1786588800123,"exchange":"HYPERLIQUID","data":{"vaultAddress":"0x2222222222222222222222222222222222222222","exchangeOrderId":"123456789","symbol":"BTC"}}'
Success response: Hyperliquid
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800456,
"data": {
"exchangeOrderId": "123456789",
"status": "CANCELED"
}
}
Request example: HabitTrade
HabitTrade does not support order cancellation; the request below always returns FEATURE_UNSUPPORTED, and the exchangeOrderId here is only a placeholder.
curl 'https://<api-host>/api/r25/trade/order/cancel' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds-or-milliseconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"ts":1787663934432,"exchange":"HABITTRADE","data":{"vaultAddress":"0xdf5fb7aa20486d1b65cbb974e5da102e7afebb08","exchangeOrderId":"62f917df0a7f483e9783d8fd4b7b8115","symbol":"SKHYs"}}'
Error response: HabitTrade
{
"code": "FEATURE_UNSUPPORTED",
"message": "HabitTrade does not support order cancel",
"timestamp": 1787663934523,
"data": null
}
A successful response means the cancellation request received a successful result. If you receive UPSTREAM_RESULT_UNKNOWN, query the order status first; do not assume that cancellation either failed or succeeded.
12.4 Close Position
Method + Path
POST /api/r25/trade/position/close
data** request fields**
| Field | Type | Hyperliquid | HabitTrade | Description |
|---|---|---|---|---|
vaultAddress | String | Required | Required | Vault contract address; the current caller must be authorized to operate it. |
symbol | String | Required | Either symbol or tokenAddress | Asset identifier to close, used as provided. For HabitTrade, either symbol or tokenAddress is required. |
quantity | String | Optional | Optional | Partial-close quantity represented as a decimal string and subject to quantity precision rules. When omitted, the request is treated as a full close. |
maxSlippageBps | Integer / String | Required, 1..1000 | Required | Maximum slippage in BPS; the valid HabitTrade range follows its trading rules. |
closeMode | String | Optional | Not used | For Hyperliquid, explicitly passing PARTIAL returns FEATURE_UNSUPPORTED; FULL or an omitted value may be used with the optional quantity. For HabitTrade, the presence of quantity determines whether the close is full or partial. |
tokenAddress | String | Not used | Either symbol or tokenAddress | Contract address of the HabitTrade asset to close; either symbol or tokenAddress is required, and INVALID_REQUEST is returned when both are missing. |
Request example: Hyperliquid full close
curl 'https://<api-host>/api/r25/trade/position/close' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds-or-milliseconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"ts":1787625645550,"exchange":"HYPERLIQUID","data":{"vaultAddress":"0x7097732c73b74e94d6e8cc9e77c287757a17afdc","symbol":"ETH","closeMode":"FULL","maxSlippageBps":50}}'
Success response: Hyperliquid
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1787625646517,
"data": {
"orderId": "HYPERLIQUID:525796683535",
"exchangeOrderId": "525796683535",
"status": "PENDING",
"acceptedAt": 1787625646517,
"encodedData": null
}
}
Request example: HabitTrade full close
curl 'https://<api-host>/api/r25/trade/position/close' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds-or-milliseconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"ts":1787736302848,"exchange":"HABITTRADE","data":{"vaultAddress":"0xd12041f181cbd0ec66b459de1f5ce219254c62df","symbol":"SPCHs","tokenAddress":"0x804688f293c15a5454586217a69f1cb36c20e15b","maxSlippageBps":"50"}}'
Success response: HabitTrade
{
"code": "200",
"message": "SUCCESS",
"timestamp": 1787736306910,
"data": {
"orderId": "HABITTRADE:3973e337de6c4de08cce2682bae8c2d1",
"exchangeOrderId": "3973e337de6c4de08cce2682bae8c2d1",
"status": "BUILT",
"acceptedAt": 1787736306910,
"encodedData": "0xfca9bd9e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002079221cb9c824c72098e5c5b4f56869f24f3ff75138f3559d60feecacdbe3362d000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000804688f293c15a5454586217a69f1cb36c20e15b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c879c018db60520f4355c26ed1a6d572cdac181500000000000000000000000000000000000000000000000000000000008954400000000000000000000000000000000000000000000000000000006a8eb7fa000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
}
}
A successful close-position response has the same structure as the create-order response in Section 12.2; the examples above show both exchanges. Hyperliquid returns status=PENDING and encodedData=null; HabitTrade returns status=BUILT with the corresponding encodedData.
13. Webhook Callbacks
13.1 Actual Callback Request
The platform sends JSON via POST to the configured callbackUrl:
POST /openapi/events HTTP/1.1
Host: hooks.partner.example
Content-Type: application/json
Authorization: Bearer <callbackApiKey>
X-Delivery-Id: <deliveryId>
X-Timestamp: <unix-seconds>
Header descriptions:
| Header | Description |
|---|---|
Content-Type | Fixed as application/json. |
Authorization | Fixed as Bearer <callbackApiKey> and uses the callback API key configured by both parties. |
X-Delivery-Id | The unique ID of this logical delivery; it stays the same across retries of the same delivery, and partners must use it for idempotency. |
X-Timestamp | Unix seconds at the time the platform sends the request. |
The Webhook currently always carries a Bearer API Key and does not send HMAC or other signature headers. Partners should protect the transport with HTTPS and use X-Delivery-Id for deduplication; to restrict the source, configure a network-layer whitelist.
13.2 DEPLOYED / GRAY / OFFICIAL Payload
All three event types use the same payload structure. Notifications are sent to active subscriptions of the partner to which the Vault belongs, provided those subscriptions include the corresponding event type. The stages are separate events: subscribing only to DEPLOYED does not include GRAY or OFFICIAL. Deduplicate retries by X-Delivery-Id, not by Vault address alone.
Field descriptions:
| Field | Type | Description |
|---|---|---|
eventType | String | Vault lifecycle event: DEPLOYED (deployment completed), GRAY (canary publication), or OFFICIAL (official publication). |
occurredAt | String | ISO 8601 offset time in Asia/Hong_Kong. |
data.vaultAddress | String | The Vault contract address associated with the event, normalized to lowercase. |
data.metadataPath | String | Relative path to query the latest metadata; the address value is URL-encoded. |
{
"eventType": "DEPLOYED",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"vaultAddress": "0x1111111111111111111111111111111111111111",
"metadataPath": "/api/r25/standard-vault/metadata?vaultAddress=0x1111111111111111111111111111111111111111"
}
}
GRAY example:
{
"eventType": "GRAY",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"vaultAddress": "0x1111111111111111111111111111111111111111",
"metadataPath": "/api/r25/standard-vault/metadata?vaultAddress=0x1111111111111111111111111111111111111111"
}
}
OFFICIAL example:
{
"eventType": "OFFICIAL",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"vaultAddress": "0x1111111111111111111111111111111111111111",
"metadataPath": "/api/r25/standard-vault/metadata?vaultAddress=0x1111111111111111111111111111111111111111"
}
}
On receipt, you can append metadataPath to https://<api-host> and re-sign a call to the query endpoint per Section 3.
13.3 Channel and Refcode Change Payload
CHANNEL_CREATED, CHANNEL_UPDATED, and CHANNEL_STATUS_CHANGED use:
{
"eventType": "CHANNEL_UPDATED",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"channelCode": "CHANNEL_EXAMPLE",
"refcode": null,
"commissionPath": "/api/r25/channel-distribution/commission"
}
}
REFCODE_CREATED and REFCODE_UPDATED also include refcode:
{
"eventType": "REFCODE_CREATED",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"channelCode": "CHANNEL_EXAMPLE",
"refcode": "REF_EXAMPLE",
"commissionPath": "/api/r25/channel-distribution/commission"
}
}
Field descriptions:
| Field | Type | Applicable events | Description |
|---|---|---|---|
eventType | String | All | Specific Rebate event type. |
occurredAt | String | All | ISO 8601 offset time in Asia/Hong_Kong. |
data.channelCode | String | All channel/refcode events | Channel code. |
data.refcode | String | Refcode events only | Refcode; null for other channel events. |
data.commissionPath | String | All | Fixed as /api/r25/channel-distribution/commission. |
13.4 Rate and Distribution Plan Change Payload
CHANNEL_REBATE_RATE_CHANGED includes both the channel and the Vault:
{
"eventType": "CHANNEL_REBATE_RATE_CHANGED",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"channelCode": "CHANNEL_EXAMPLE",
"vaultAddress": "0x1111111111111111111111111111111111111111",
"commissionPath": "/api/r25/channel-distribution/commission"
}
}
VAULT_DISTRIBUTION_PLAN_CHANGED only provides Vault locating information, and channelCode returns null:
{
"eventType": "VAULT_DISTRIBUTION_PLAN_CHANGED",
"occurredAt": "2026-08-13T16:00:00+08:00",
"data": {
"channelCode": null,
"vaultAddress": "0x1111111111111111111111111111111111111111",
"commissionPath": "/api/r25/channel-distribution/commission"
}
}
Field descriptions:
| Field | Type | Applicable events | Description |
|---|---|---|---|
eventType | String | All | Specific Rebate event type. |
occurredAt | String | All | ISO 8601 offset time in Asia/Hong_Kong. |
data.channelCode | String | CHANNEL_REBATE_RATE_CHANGED | Channel code; null in Vault distribution plan events. |
data.vaultAddress | String | All | Vault contract address. |
data.commissionPath | String | All | Fixed as /api/r25/channel-distribution/commission. |
13.5 Delivery Success, Timeouts, and Retries
- Any HTTP
2xxreturned by the partner is treated as a successful receipt; the response body does not participate in the success determination. - The platform connection timeout is 3 seconds; the response read timeout is 10 seconds; HTTP redirects are not followed.
- The platform reads at most the first 4000 bytes of the partner's response body.
- A single delivery is attempted at most 3 times, including the first. After a recoverable failure, the first retry waits 60 seconds and the second waits 300 seconds.
- HTTP
401,403, and410immediately terminate the delivery and disable the corresponding Webhook configuration. - A callback request that cannot be constructed, or a callback address that fails the pre-delivery security review, terminates the delivery and disables the corresponding Webhook configuration.
- Other failures are terminated after the 3rd attempt. After the partner recovers, terminated deliveries are not retried automatically.
- Because network timeouts may cause "the partner has processed the request but the platform received no response", you must use
X-Delivery-Idfor idempotent processing and return2xxas quickly as possible.
14. Integration Notes and Current Limitations
- The
vaultAddressof/api/r25/standard-vault/metadatais a required query parameter: omission returns-1005, while a blank value or an address outside the accessible Vault set returns-1008; if the address passes the access check but no metadata is found, the response uses-1010. - All response fields documented here are included; fields with no available value are returned as
null. - All business endpoints require Ed25519 V2 authentication. The signature is based on the raw body bytes and the canonical query; rewriting the request by a proxy layer, SDK, or serializer may cause signature verification to fail.
- The HTTP status of business responses remains
200; you must checkcodein the response JSON. - The Webhook callback always carries
Authorization: Bearer <callbackApiKey>and currently sends no HMAC or other signature header. Use HTTPS, source-side network controls (where applicable), andX-Delivery-Idto protect the receiver with idempotency. - Do not use JSON floating-point numbers for on-chain amounts marked as String in this document; decimal JSON numbers should also be parsed with an arbitrary-precision decimal type.