Skip to main content

REST API

Market Data Integration​

To reduce latency from intermediary forwarding when retrieving market data, partners should connect directly to the official APIs of Hyperliquid and Stove to obtain market data from each platform. Refer to the following official Open API documentation for integration details and interface requirements:

Request methods, authentication requirements, and rate limits for these market data APIs are governed by each platform's official documentation.

Environment Information​

EnvironmentBase URL
Productionhttps://api-studio.r25.xyz

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; HYPERLIQUID and HABITTRADE are currently integrated.
  • Webhook: receive configured Vault and 7 types of Rebate change notifications; eventType identifies 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 timestamp in the unified response is a Unix timestamp in milliseconds.
  • Partners should use Unix seconds for the authentication header X-Timestamp. Unix milliseconds and yyyy-MM-dd HH:mm:ss in the platform time zone are also accepted.
  • The ts field 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 header X-Timestamp, and both must be provided.
  • The date field of Standard Vault NAV history is a millisecond timestamp string corresponding to 00:00 UTC of the given day.
  • The requestBlockTime and settleBlockTime of transaction records are in epoch seconds.
  • The Webhook header X-Timestamp is in Unix seconds.
  • The occurredAt field in a Webhook payload is an ISO 8601 offset time converted to Asia/Hong_Kong; the current offset is +08:00.

2.3 Number and Null Conventions​

  • On-chain amounts or quantities exposed as String must be handled as strings; do not convert them to a JavaScript Number or 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. 20 means 20%.
  • 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:

HeaderRequiredDescription
X-Client-IdYesThe unique partner identifier assigned by the platform and associated with the partner's Ed25519 public key.
X-TimestampYesRequest time. Unix seconds recommended; Unix milliseconds or yyyy-MM-dd HH:mm:ss are also accepted.
X-SignatureYesThe 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 the X-Timestamp request 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 is e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.

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:

  1. Only the following keys are allowed: pageNumber, pageSize, recordType, address, status, requestId, vaultAddress, shares, assets, startDate, endDate, channelCode, refcode, transactionType, eventTime.
  2. Sort by key in ascending lexicographic order.
  3. 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.
  4. Each entry is composed as key=value, then joined with &.
  5. Repeating the same key makes the request invalid.
  6. The query parameters sent in the URL must exactly match those used to build the Canonical Query, including their decoded values. Do not include parameters outside the allow list.

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:ss is 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 allowed in Section 3.3 of this document. 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:

FieldTypeDescription
codeStringBusiness response code; success is "200". Generic failures use the string form of a negative number; Trading REST business failures use uppercase enum strings.
messageStringSUCCESS on success; an error explanation on failure, sometimes with the specific reason appended.
timestampLongThe Unix timestamp in milliseconds at which the server generated the response.
dataAny JSON valueBusiness 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​

codeDefault messageMeaning
-1001auth headers missingMissing authentication headers; also used to reject duplicate query keys. The specific message explains the reason.
-1002timestamp expired or invalidThe timestamp cannot be parsed or falls outside the ±300 second window.
-1003invalid access keyThe X-Client-Id is unknown, or no public key is currently available on the server.
-1004signature mismatchThe Ed25519 signature does not match, or the signature hex format/length is incorrect.
-1005form validation errQuery/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.
-1006auth failedAuthentication failed.
-1007too many requestsThe request rate limit was triggered.
-1008vault not permittedThe current partner identity is not permitted to access the specified Vault.
-1017request replayedAn identical signed request was resent within the authentication time window.
-1010query metadata failedThe metadata query failed; a Standard Vault metadata request with a missing or unknown address also uses this code.
-1012query nav history failedThe Standard Vault NAV history query failed, or the returned data does not conform to the contract.
-1019query channel distribution failedThe Rebate query failed; when a valid business error message is available, that message takes precedence.
-1020preview contract call failedThe preview calculation failed.
-1021query positions failedThe Standard Vault current positions query failed or the Vault address is empty.
-1022query vault events failedThe Vault events query failed.
-1023vault configuration failedThe Vault configuration update failed, the Vault address could not be mapped uniquely, or the downstream response violated the contract.
-5000server errorAn 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:

codeMeaningRetry advice
INVALID_REQUESTThe request envelope, required fields, enums, values, or ranges are invalid.Correct the request and retry.
VAULT_NOT_PERMITTEDThe 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_EXCHANGEexchange is missing or is not HYPERLIQUID / HABITTRADE.Correct the request and retry.
FEATURE_UNSUPPORTEDThe 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_TICKThe price does not conform to the current exchange's price precision configuration.Correct to a valid price precision and retry.
INVALID_SIZE_STEPThe quantity does not conform to the current exchange's quantity precision configuration.Correct to a valid quantity precision and retry.
EXCHANGE_REJECTEDThe exchange returned a business rejection or failure result.Correct according to the message; do not retry unconditionally.
UPSTREAM_RESULT_UNKNOWNA 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_ERRORThe 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 Standard Vault, Preview, Rebate channel distribution, transaction records, and Trading REST endpoints are rate-limited along the following two dimensions independently:

Limit dimensionAllowed request frequency per endpoint
IPUp to 60 requests per 60 seconds
X-Client-IdUp to 120 requests per 1 hour
  • The limit is counted per endpoint independently; request counts are not shared across endpoints.
  • When either the IP or the X-Client-Id dimension reaches the limit, the current request is rejected.
  • When the limit is exceeded, the HTTP status remains 200 and the business response code is -1007 with the default message too many requests.
  • Rate-limit responses return a suggested wait time via the Retry-After header, in seconds and rounded up; partners should retry after that time.

5. Endpoint Overview​

CategoryMethodPathRequest locationCurrent status
Standard VaultGET/api/r25/standard-vault/metadataQueryAvailable; vaultAddress is actually required
Standard VaultGET/api/r25/standard-vault/vaultListQuery (pageNumber, pageSize)Available
Standard VaultGET/api/r25/standard-vault/eventsQuery (eventTime, pageNumber, pageSize)Available
Standard VaultGET/api/r25/standard-vault/nav/historyQueryAvailable
Standard VaultGET/api/r25/standard-vault/positionsQueryAvailable; vaultAddress required
Standard VaultPOST/api/r25/standard-vault/configurationJSON BodyAvailable
Standard Vault PreviewGET/api/r25/standard-vault/preview/mintQueryAvailable
Standard Vault PreviewGET/api/r25/standard-vault/preview/redeemQueryAvailable
Standard Vault PreviewGET/api/r25/standard-vault/preview/depositQueryAvailable
Standard Vault PreviewGET/api/r25/standard-vault/preview/withdrawQueryAvailable
RebateGET/api/r25/channel-distribution/commissionQueryAvailable
RebateGET/api/r25/channel-distribution/transactionsQueryAvailable
RebateGET/api/r25/channel-distribution/merkle-proofs/batchQueryAvailable
Transaction recordsGET/api/r25/standard-vault/transaction/recordsQueryUnified transaction records entry
Trading RESTPOST/api/r25/trade/order/createJSON BodyAvailable; supports Hyperliquid / HabitTrade
Trading RESTPOST/api/r25/trade/order/cancelJSON BodyHyperliquid only
Trading RESTPOST/api/r25/trade/position/closeJSON BodyAvailable; rules differ by exchange

6. Standard Vault Endpoints​

6.1 Common Metadata Response Structure​

Standard Vault Metadata returns the layered VaultMetadataResponse structure. The response is grouped into basic info, 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:

FieldTypeDescription
vaultBasicInfoObjectVault basic information.
vaultMetricsObjectVault current dynamic metrics.
transactionConfigInfoObjectVault subscription/redemption, limits, settlement, and fee configuration.
assetConfigObjectShare token and underlying asset configuration.
accessControlObjectCurator and subscription whitelist configuration.
contractConfigObjectCore contract and module contract configuration.
riskConfigObjectVault risk configuration.
prosperInfoObjectProsper external integration configuration.

vaultBasicInfo fields:

FieldTypeDescription
vaultNameStringVault name; null when there is no data.
vaultLogoUrlStringVault logo URL; null when there is no data.
curationStrategyDescriptionStringStrategy description configured by the Curator; null when there is no data.
chainObjectChain information of the Vault; fields are listed in the table below.
offlineBooleanWhether the Vault is offline; null when there is no data.
deployTimeStringContract deployment time in the format yyyy-MM-dd'T'HH:mm:ss with no time-zone offset.

vaultBasicInfo.chain fields:

FieldTypeDescription
chainIdStringChain ID.
chainNameStringChain name.

vaultMetrics fields:

FieldTypeDescription
tvlStringTotal value locked, represented as a decimal string.
cFundingStringThe raw on-chain amount of cumulative net USDC subscriptions by the fund manager; returns "0" when the Curator address or aggregation result is missing.
apyStringAnnualized yield in percent; e.g. "8.25" means 8.25%.
navStringCurrent unit NAV, returned as a plain decimal string with insignificant trailing zeros removed.
currentShareHoldersStringCurrent number of share holder addresses.
shareTokenTotalSupplyStringCurrent share token total supply; for Standard Vaults it is already converted to the Share Token precision.

transactionConfigInfo fields:

FieldTypeDescription
flexibleSubAndRedeemBooleanWhether flexible subscription and redemption is supported. When the value is true, all three windows return null, and both depositAvailable and redeemAvailable are true.
cutOffTimeStringSettlement time.
depositTokenObjectSubscription and redemption token name, address, and decimals; returns null only when all three fields are null.
subscriptionWindowObjectSubscription window; null when flexible subscription/redemption applies or there is no data.
redemptionWindowObjectRedemption window; null when flexible subscription/redemption applies or there is no data.
lockWindowObjectProduct lock window; null when flexible subscription/redemption applies or there is no data.
limitsObjectSubscription/redemption and overall Vault limits.
settlementObjectSubscription/redemption settlement configuration.
feeRatesObjectVault fee rate configuration.
depositAvailableBooleanWhether 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.
redeemAvailableBooleanWhether 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:

FieldTypeDescription
tokenNameStringConfigured subscription and redemption token name; null when missing.
addressStringSubscription and redemption token contract address; null when no matching data exists.
decimalsStringSubscription and redemption token decimals; null when no matching data exists.

Common fields of subscriptionWindow, redemptionWindow, and lockWindow:

FieldTypeDescription
startDateStringWindow start time in the format yyyy-MM-dd'T'HH:mm:ss with no time-zone offset.
endDateStringWindow end time in the format yyyy-MM-dd'T'HH:mm:ss with no time-zone offset.
periodDaysStringWindow duration in days, returned as a string.

transactionConfigInfo.limits fields:

FieldTypeDescription
depositObjectPer-order subscription amount limits.
deposit.minAmountStringMinimum subscription amount per order. USD
deposit.maxAmountStringMaximum subscription amount per order. USD
redemptionObjectPer-order redemption limits.
redemption.minSharesStringMinimum redemption share quantity per order. Standard Vaults currently return "0" to indicate no limit. share
redemption.maxSharesStringMaximum redemption share quantity per order. Standard Vaults currently return "0" to indicate no limit. share
redemption.minAssetsStringMinimum redemption asset quantity per order. Standard Vaults currently return "0" to indicate no limit. share
vaultObjectOverall Vault limits.
vault.maxCapStringMaximum share supply of the Vault; not a fixed value.
vault.maxTvlStringMaximum TVL of the Vault. Standard Vaults currently return "0" to indicate no limit. USD

Standard Vault "0" special semantics: Currently the Standard Metadata fields redemption.minShares, redemption.maxShares, redemption.minAssets, and vault.maxTvl always 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:

FieldTypeDescription
settleTypeStringSettlement type: "0" means synchronous, "1" means asynchronous.
depositSettlementStringSubscription settlement cycle, returned as a numeric string such as "0", "1"; no T+ prefix is added.
redemptionSettlementStringRedemption settlement cycle, returned as a numeric string such as "0", "1"; no T+ prefix is added.

transactionConfigInfo.feeRates fields:

FieldTypeDescription
depositFeeRateStringUser subscription fee rate, in percent.
withdrawalFeeRateStringUser withdrawal fee rate, in percent.
performanceFeeRateStringVault performance fee rate, in percent.
managementFeeRateStringVault management fee rate, in percent.

assetConfig fields:

FieldTypeDescription
shareTokenObjectStatic information of the share token.
underlyingAssetsArrayUnderlying asset list; element fields are listed in the table below.

assetConfig.shareToken fields:

FieldTypeDescription
addressStringShare token contract address.
addressAtBlockStringShare token deployment block height, returned as a string.
decimalsStringShare token decimals, returned as a string.
symbolStringShare token symbol.
nameStringShare token name.

assetConfig.underlyingAssets[] fields:

FieldTypeDescription
targetVaultAddressStringTarget Vault address associated with the underlying asset.
vaultTokenObjectUnderlying asset token information.
vaultToken.addressStringUnderlying asset token contract address.
vaultToken.nameStringUnderlying asset token name.
vaultToken.symbolStringUnderlying asset token symbol.
vaultToken.decimalsStringUnderlying asset token decimals, returned as a string.
adapterObjectUnderlying asset Adapter information.
adapter.idStringAdapter identifier.
adapter.typeStringAdapter type.
percentageBpsStringInitial asset allocation ratio, returned as a string without ratio conversion.
logoUrlStringUnderlying asset logo URL.

accessControl fields:

FieldTypeDescription
curatorAddressStringCurator permission address.
subscriptionWhitelistObjectSubscription whitelist configuration.
subscriptionWhitelist.enabledBooleanWhether the subscription whitelist restriction is enabled.
subscriptionWhitelist.contractObjectSubscription whitelist guard contract deployment information.

contractConfig fields:

FieldTypeDescription
coreContractObjectVault core contract deployment information.
moduleContractsObjectVault module contract deployment information.

Common fields of coreContract, subscriptionWhitelist.contract, and each module contract:

FieldTypeDescription
addressStringOn-chain contract address.
addressAtBlockStringContract deployment block height, returned as a string.

contractConfig.moduleContracts fields:

FieldTypeDescription
feeRouterContractObjectFee router contract.
entryFixedBpsFeeContractObjectSubscription fixed-bps fee contract.
exitFixedBpsFeeContractObjectRedemption fixed-bps fee contract.
timeAccrualFeeContractObjectTime-accrual fee contract.
hwmPerformanceFeeContractObjectHigh-water-mark performance fee contract.
commissionContractObjectProject commission collection contract.
navContractObjectNAV query contract.

riskConfig fields:

FieldTypeDescription
riskLevelStringVault risk level.
strategyRiskDisclosureTextStringStrategy risk disclosure text.
riskDisclosureStringVault risk disclosure body text.

prosperInfo fields:

FieldTypeDescription
prosperTokenNameStringProsper token name identifier.
rewardStringTarget Reward contract address.
validProsperStringWhether to include the Pharos token: "1" means included, "0" means not included.

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

FieldTypeRequiredDefault/EnumDescription
vaultAddressStringYesNoneVault 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 6.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.

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",
"chain": {
"chainId": "1",
"chainName": "Ethereum"
},
"offline": false,
"deployTime": "2026-07-29T14:43:52"
},
"vaultMetrics": {
"tvl": "125000000",
"cFunding": "1000000",
"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"
},
"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",
"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"
}
}
},
"riskConfig": {
"riskLevel": "MEDIUM",
"strategyRiskDisclosureText": null,
"riskDisclosure": null
},
"prosperInfo": {
"prosperTokenName": "pUSDY",
"reward": "0xcccccccccccccccccccccccccccccccccccccccc",
"validProsper": "1"
}
}
}

In the example above, the three "0" values in transactionConfigInfo.limits.redemption and the "0" in transactionConfigInfo.limits.vault.maxTvl all 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, blank, or unknown vaultAddress returns -1010. EVM address format is not currently validated; partners should still pass a standard address.
  • Only published and enabled Vaults can be queried.

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

FieldTypeRequiredDefault/EnumDescription
pageNumberIntegerNo1Page number, must be ≥ 1.
pageSizeIntegerNo10Page 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**

FieldTypeDescription
listObject[]Vault info in the current page; [] when there is no data.
list[].vaultAddressStringVault contract address.
list[].createTimeLongVault creation time, Unix millisecond timestamp.
pageNumberIntegerCurrent page number.
pageSizeIntegerPage size.
hasNextBooleanWhether 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 list is an object containing vaultAddress and createTime.
  • Request validation fails when pageNumber is less than 1 or pageSize is outside the 1–100 range.

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

FieldTypeRequiredDefault/FormatDescription
eventTimeStringYesyyyy-MM-dd HH:mm:ssQuery start time, inclusive; interpreted in Asia/Hong_Kong (UTC+8).
pageNumberIntegerNo1Page number, must be ≥ 1.
pageSizeIntegerNo10Page size, in the range 1 to 100.

Request example

curl --get 'https://<api-host>/api/r25/standard-vault/events' \
--data-urlencode 'eventTime=2026-08-24 16:00:00' \
--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**

FieldTypeDescription
listObject[]Vault events in the current page; [] when there is no data.
list[].eventTypeStringVault lifecycle event type: DEPLOYED, GRAY, or OFFICIAL.
list[].coreVaultAddressStringCore Vault contract address.
list[].changeTypeStringChange type.
list[].changeTimeLongChange time, Unix millisecond timestamp.
list[].transactionHashStringTransaction hash of the change.
list[].blockHeightLongBlock height of the change.
list[].vaultStatusStringVault status after the change.
pageNumberIntegerCurrent page number.
pageSizeIntegerPage size.
hasNextBooleanWhether 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 eventTime is missing or does not match yyyy-MM-dd HH:mm:ss, when pageNumber is less than 1, or when pageSize is outside the 1–100 range.
  • Returns -1022 when the query fails.
  • The endpoint returns the actual Vault lifecycle type of each event in eventType.
  • Nullable fields in a list item return null when no value is currently available.

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

FieldTypeRequiredDefault/FormatDescription
vaultAddressStringYesVault contract addressUsed to locate the Standard Vault.
startDateStringNoyyyy-MM-ddStart date for the NAV query.
endDateStringNoyyyy-MM-ddEnd 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**

FieldTypeDescription
listArrayDaily NAV records; [] when there is no data.
list[].dateStringMillisecond timestamp string corresponding to 00:00 UTC of the day.
list[].navNumberUnit 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

  • Returns -1012 when vaultAddress is missing or empty, or when the NAV query fails.
  • Only date and nav are returned.

6.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, and 24-hour price change percentage.

Method + Path

GET /api/r25/standard-vault/positions

Request location

Query; no request body.

Request fields

FieldTypeRequiredDefault/FormatDescription
vaultAddressStringYesNoneVault 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 [].

FieldTypeDescription
[].symbolStringAsset symbol.
[].addressStringAsset contract address.
[].priceNumberCurrent price per asset unit in USD.
[].weightNumberCurrent position weight in percent; e.g. 25.5 means 25.5%.
[].logoUrlStringAsset logo URL.
[].priceChangeNumberPrice 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%.

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
},
{
"symbol": "USDY",
"address": "0x4444444444444444444444444444444444444444",
"price": 1.0250,
"weight": 60.0000,
"logoUrl": "https://static.example.com/usdy.png",
"priceChange": 0.9300
}
]
}

Specific limits

  • Returns -1021 when vaultAddress is missing or blank, or when the positions query fails.
  • When symbol, address, price, weight, logoUrl, or priceChange has no value, the corresponding field returns null.
  • The endpoint returns the positions list and does not include total AUM, asset quantity, holding quantity, or holding value.

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

MethodPathInputContract preview result
GET/api/r25/standard-vault/preview/mintsharesassets required to deposit
GET/api/r25/standard-vault/preview/redeemsharesassets redeemable
GET/api/r25/standard-vault/preview/depositassetsshares mintable
GET/api/r25/standard-vault/preview/withdrawassetsshares to burn

Request location

Query; no request body.

Request fields

FieldTypeRequiredApplicable endpointsDescription
vaultAddressStringYesAll0x or 0X prefix plus 40 hexadecimal characters.
sharesStringYesmint, redeemOn-chain minimum-unit quantity of shares, as a uint256 decimal string; only 0 or a non-negative integer not starting with 0 is allowed.
assetsStringYesdeposit, withdrawOn-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**

FieldTypeDescription
vaultAddressStringEchoes the Vault contract address from the request.
sharesStringOn-chain minimum-unit quantity of shares; echoed from the input in mint/redeem, and the contract result in deposit/withdraw.
assetsStringOn-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/assets must not exceed 2^256 - 1; an invalid format or value range returns -1005.
  • Returns -1020 when the preview calculation fails.

6.8 Vault Page Configuration​

Purpose

After completing canary or official publication processing for a Vault, the partner uses this endpoint to report the access link and processing status.
When eventType=GRAY, dappLink is the canary access link. When eventType=OFFICIAL, dappLink is the official access link.

Method + Path

POST /api/r25/standard-vault/configuration

Request location

JSON Body; Content-Type: application/json. The body SHA-256 for signing must be computed from the final sent raw JSON bytes.

Request fields

FieldTypeRequiredFormat/EnumDescription
dappLinkStringNoMax 2048 charactersAccess link. It is the canary link when eventType=GRAY and the official link when eventType=OFFICIAL. Omit it when no link is available.
eventTypeStringYesGRAY, OFFICIALPublication stage associated with this report; values are case-sensitive.
statusStringYesSee the table belowProcessing result; values are case-sensitive.
vaultAddressStringYes0x or 0X + 40 hexadecimal charactersVault on-chain contract address.
remarkStringNoNo additional format restrictionStatus details, such as a delisting or rejection reason.

Status values

statusMeaningWhen used
GRAYCanary publishedThe canary link has been generated and the Curator can access the Vault through it.
OFFICIALOfficially publishedThe Vault is displayed in the Dapp Vaults list.
DELISTEDDelistedThe Vault has been removed from the Dapp.
REJECTEDRejectedThe Vault did not pass the Dapp-side review.
OTHEROtherAn exceptional situation that cannot be classified under the statuses above.

Canary publication request example

curl 'https://<api-host>/api/r25/standard-vault/configuration' \
-X POST \
-H 'Content-Type: application/json' \
-H 'X-Client-Id: <client-id>' \
-H 'X-Timestamp: <unix-seconds>' \
-H 'X-Signature: <128-char-ed25519-signature-hex>' \
--data-raw '{"dappLink":"https://gray.example.com/vault","eventType":"GRAY","status":"GRAY","vaultAddress":"0x1111111111111111111111111111111111111111","remark":"Canary review approved"}'

Official publication request example

{
"dappLink": "https://dapp.example.com/vault",
"eventType": "OFFICIAL",
"status": "OFFICIAL",
"vaultAddress": "0x1111111111111111111111111111111111111111",
"remark": "Official publication completed"
}

Success response

data is the configuration result returned by the Vault service. A partner may treat the configuration update as successful only when data=true.

{
"code": "200",
"message": "SUCCESS",
"timestamp": 1788480000000,
"data": true
}

Failure semantics

  • Returns -1005 when the request body, eventType, status, or vaultAddress fails validation.
  • Returns -1008 when the current partner is not permitted to operate the specified Vault.
  • Returns -1023 when the Vault address cannot be mapped uniquely, or when the Vault service returns a failed or invalid response.
  • Returns -5000 for Vault service network errors, timeouts, or other unexpected failures.

7. Rebate Channel Distribution Endpoints​

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

FieldTypeRequiredDefault/EnumDescription
channelCodeStringNoNoneOptional channel stable code; must not be blank-only when provided; leading and trailing whitespace is trimmed before use.
refcodeStringNoNoneRefcode; must not be blank-only when provided; leading and trailing whitespace is trimmed before use.
vaultAddressStringNo0x + 40 hexadecimal charactersOptional 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**

FieldTypeDescription
dataAsOfStringData statistic time point, ISO 8601 UTC.
vault.chainIdLongChain ID.
vault.vaultAddressStringCore Vault contract address.
vault.nameStringVault name.
vault.symbolStringVault share token symbol.
vault.assetAddressStringBase asset address.
vault.assetDecimalsIntegerBase asset decimals.
channel.channelCodeStringChannel code.
channel.nameStringChannel name.
channel.statusStringChannel status.
channel.payoutWallet.addressStringChannel commission payout wallet address.
channel.payoutWallet.chainCodeStringPayout wallet chain identifier.
itemsArrayRefcode-dimension distribution and commission results.
items[].refcode.codeStringRefcode.
items[].refcode.labelStringRefcode label.
items[].refcode.statusStringRefcode status.
items[].distribution.enabledBooleanWhether distribution is currently enabled.
items[].distribution.statusStringDistribution status.
items[].distribution.effectiveRates.managementRateNumberCurrent management fee rebate percentage.
items[].distribution.effectiveRates.performanceRateNumberCurrent performance fee rebate percentage.
items[].distribution.rateSourceStringSource of the currently effective rates.
items[].distribution.effectivePeriod.startTimeStringStart time of the current rule.
items[].distribution.effectivePeriod.endTimeStringEnd time of the current rule; null when there is none.
items[].commission.attributedInflowObjectCumulative valid attributed inflow, using the AssetAmount structure.
items[].commission.attributionRateNumberAttribution ratio on the Share-Seconds basis.
items[].commission.attributionRateBasisStringAttribution ratio calculation basis.
items[].commission.timeWeightedTvlObjectTime-weighted TVL, includes valuation reliability status.
items[].commission.componentsArrayCommission details split by fee, asset, and status.

AssetAmount, TimeWeightedTvl, and CommissionComponent:

StructureFieldTypeDescription
AssetAmountassetAddressStringAsset address.
AssetAmountassetDecimalsIntegerAsset decimals.
AssetAmountamountStringRaw on-chain asset quantity.
TimeWeightedTvlassetAddressStringAsset address.
TimeWeightedTvlassetDecimalsIntegerAsset decimals.
TimeWeightedTvlamountStringRaw on-chain asset quantity.
TimeWeightedTvlvaluationStatusStringValuation reliability status.
CommissionComponentfeeTypeStringFee type.
CommissionComponentassetTypeStringCommission asset type.
CommissionComponentassetAddressStringCommission asset address.
CommissionComponentassetDecimalsIntegerCommission asset decimals.
CommissionComponentamountStringRaw on-chain commission asset quantity.
CommissionComponentstatusStringCommission 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.0 means 20%, not 0.2.
  • The response does not include recalculated commission, cross-asset totals, or USD valuation.

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

FieldTypeRequiredDefault/EnumDescription
channelCodeStringYesNoneChannel stable code; leading and trailing whitespace is trimmed before use.
refcodeStringNoNoneRefcode; must not be blank-only when provided.
vaultAddressStringYes0x + 40 hexadecimal charactersCore Vault contract address; lowercased before querying.
transactionTypeStringNodeposit / withdrawCase-sensitive.
pageNumberIntegerNoDefault 1; min 1The request parameter name is pageNumber.
pageSizeIntegerNoDefault 20; range 1..100Page 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**

FieldTypeDescription
pageNumIntegerCurrent page number. Note that the response field name differs from the request's pageNumber.
pageSizeIntegerCurrent page size.
hasNextBooleanWhether a next page exists.
itemsArrayCurrent page of flows.
items[].eventIdStringUnique identifier of the rebate-chain event.
items[].chainIdLongChain ID.
items[].txHashStringTransaction hash.
items[].blockNumberLongBlock height.
items[].transactionIndexIntegerTransaction index within the block.
items[].logIndexIntegerLog index of the transaction.
items[].timeStringOn-chain event time.
items[].typeStringdeposit or withdraw.
items[].refcodeStringAttributed refcode.
items[].walletStringMasked wallet address, usually keeping only the first 6 and the last 4 characters.
items[].amount.assetAddressStringBase asset address.
items[].amount.assetDecimalsIntegerBase asset decimals.
items[].amount.amountStringRaw on-chain base asset quantity.
items[].sharesStringCorresponding 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.
  • wallet is masked and does not return the full holder address; an abnormally short value returns ****.

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

FieldTypeRequiredDefault/RestrictionDescription
channelAddressStringYes0x + 40 hexadecimal charactersChannel login address; lowercased before querying.
vaultAddressString[]YesEach item is 0x + 40 hexadecimal charactersVault 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.
pageNumberIntegerNoDefault 1; min 1Current page number.
pageSizeIntegerNoDefault 20; range 1..100Page 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**

FieldTypeDescription
authorizedVaultIdsLong[]Vault external IDs that the current Curator is authorized to query.
pageSizeIntegerCurrent page size.
pageNumberIntegerCurrent page number.
hasNextBooleanWhether a next page exists.
proofsArrayMerkle Proof results in the current page.
proofs[].vaultIdLongVault external ID.
proofs[].addressStringActual channel rebate receiving address used to generate the proof.
proofs[].amountStringClaimable amount in minimum-unit integer.
proofs[].proofString[]Merkle Proof hash path; can be an empty array when the leaf is the root.
proofs[].merkleRootStringMerkle root of the latest ALLOCATED batch.
proofs[].claimAddressStringCorresponding 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 currentCount or totalCount; use hasNext to determine whether another page is available.
  • amount is a minimum-unit on-chain integer string and must not be parsed as a floating-point number.

8. Transaction Records Endpoint​

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

FieldTypeRequiredDefault/EnumDescription
addressStringNo0x + 40 hexadecimal charactersBusiness owner wallet address; leading and trailing whitespace is trimmed and lowercased before querying.
vaultAddressStringNo0x + 40 hexadecimal charactersVault contract address; leading and trailing whitespace is trimmed and lowercased before querying.
recordTypeStringNoDEPOSIT / REDEEMCase-insensitive; an empty string means no filter; other values fail validation.
statusStringNoPENDING / CLAIMED / CANCELLEDCase-insensitive; an empty string means no filter; other values fail validation.
requestIdStringNoNoneAsync request ID; a blank value is treated as no filter.
pageNumberIntegerNoDefault 1; min 1Page number.
pageSizeIntegerNoDefault 100; range 1..100Page 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**

FieldTypeDescription
listArrayTransaction records in the current page.
pageNumberIntegerCurrent page number.
pageSizeIntegerCurrent page size.
totalLongTotal number of matching records.
hasNextBooleanWhether a next page exists.
list[].requestTxHashStringRequest transaction hash.
list[].requestTypeStringDEPOSIT or REDEEM.
list[].vaultAddressStringVault contract address.
list[].statusStringPENDING, CLAIMED, or CANCELLED.
list[].assetsStringAsset quantity, raw on-chain un-scaled integer string.
list[].sharesStringShare quantity, raw on-chain un-scaled integer string.
list[].chainIdLongChain ID.
list[].requestBlockNumberLongBlock height of the request transaction.
list[].requestBlockTimeLongRequest transaction block time, epoch seconds.
list[].requestIdStringAsync request ID; null for synchronous transactions.
list[].settleTxHashStringSettlement transaction hash; null when not settled.
list[].settleBlockTimeLongSettlement transaction block time, epoch seconds; null when not settled.
list[].walletAddressStringBusiness 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

  • assets and shares are 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.
  • recordType and status allow only the current business enums listed in the table; any other non-empty value returns -1005.
  • Both address and vaultAddress are optional. When no business filter is provided, all available records are returned according to the pagination parameters.

9. Trading REST Write Endpoints​

9.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"
}
}
FieldTypeRequiredDescription
tsLongYesRequest 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.
exchangeStringYesUse uppercase HYPERLIQUID or HABITTRADE; values are case-sensitive.
dataObjectYesThe business parameter object for the current operation. The request fails when it is missing or is not a JSON Object.
data.vaultAddressStringYesVault 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.

9.2 Create Order​

Method + Path

POST /api/r25/trade/order/create

data** request fields**

FieldTypeHyperliquidHabitTradeDescription
vaultAddressStringRequiredRequiredVault contract address; the current caller must be authorized to operate it.
symbolStringRequiredRequiredTrading asset identifier, used as provided.
sideStringRequiredRequiredBUY or SELL, case-insensitive.
orderTypeStringRequiredRequiredLIMIT or MARKET, case-insensitive.
quantityStringRequiredRequiredOrder quantity decimal string; must conform to the valid quantity precision of the current exchange.
priceStringRequired for LIMITShould be provided for LIMITLimit price. Hyperliquid rejects a request when this field is missing; valid HabitTrade values follow its trading rules.
maxSlippageBpsInteger / StringRequired for MARKETRequiredMaximum 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.
leverageStringRequiredNot usedLeverage multiplier represented as a decimal string.
timeInForceStringOptionalNot usedHyperliquid time-in-force value; supported values must be agreed with the exchange.
reduceOnlyBooleanOptional, default falseNot usedReduce-only flag.
tokenAddressStringNot usedOptionalHabitTrade asset contract address; whether omission is accepted follows HabitTrade rules.

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

{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800456,
"data": {
"orderId": "HYPERLIQUID:123456789",
"exchangeOrderId": "123456789",
"status": "PENDING",
"acceptedAt": 1786588800400,
"encodedData": null
}
}
FieldTypeDescription
orderIdStringPlatform-normalized order ID, usually <exchange>:<exchangeOrderId>; may be null when no exchange order ID is available.
exchangeOrderIdStringExchange order ID; may be null when no value is available.
statusStringPENDING when Hyperliquid successfully accepts; BUILT when HabitTrade successfully builds the transaction to be signed.
acceptedAtLongAcceptance time in Unix milliseconds. Hyperliquid uses the exchange-provided time when available, otherwise the API response time; HabitTrade uses the API response time.
encodedDataStringABI-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.

9.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**

FieldTypeRequiredDescription
vaultAddressStringYesVault contract address; the current caller must be authorized to operate it.
exchangeOrderIdStringYesHyperliquid order ID, must be parseable as a Long. When passing the platform orderId, strip the HYPERLIQUID: prefix first.
symbolStringYesTrading 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

{
"code": "200",
"message": "SUCCESS",
"timestamp": 1786588800456,
"data": {
"exchangeOrderId": "123456789",
"status": "CANCELED"
}
}

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.

9.4 Close Position​

Method + Path

POST /api/r25/trade/position/close

data** request fields**

FieldTypeHyperliquidHabitTradeDescription
vaultAddressStringRequiredRequiredVault contract address; the current caller must be authorized to operate it.
symbolStringRequiredRequiredAsset identifier to close, used as provided.
quantityStringOptionalOptionalPartial-close quantity represented as a decimal string and subject to quantity precision rules. When omitted, the request is treated as a full close.
maxSlippageBpsInteger / StringRequired, 1..1000RequiredMaximum slippage in BPS; the valid HabitTrade range follows its trading rules.
closeModeStringOptionalNot usedFor 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.
tokenAddressStringNot usedOptionalHabitTrade asset contract address.

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":1786588800123,"exchange":"HABITTRADE","data":{"vaultAddress":"0x2222222222222222222222222222222222222222","symbol":"ETH","tokenAddress":"0x3333333333333333333333333333333333333333","maxSlippageBps":50}}'

A successful close-position response has the same structure as the create-order response in Section 9.2. Hyperliquid returns status=PENDING and encodedData=null; HabitTrade returns status=BUILT with the corresponding encodedData.

10. Webhook Callbacks​

10.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:

HeaderDescription
Content-TypeFixed as application/json.
AuthorizationFixed as Bearer <callbackApiKey> and uses the callback API key configured by both parties.
X-Delivery-IdThe unique ID of this logical delivery; it stays the same across retries of the same delivery, and partners must use it for idempotency.
X-TimestampUnix 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.

10.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:

FieldTypeDescription
eventTypeStringVault lifecycle event: DEPLOYED (deployment completed), GRAY (canary publication), or OFFICIAL (official publication).
occurredAtStringISO 8601 offset time in Asia/Hong_Kong.
data.vaultAddressStringThe Vault contract address associated with the event, normalized to lowercase.
data.metadataPathStringRelative 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.

10.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:

FieldTypeApplicable eventsDescription
eventTypeStringAllSpecific Rebate event type.
occurredAtStringAllISO 8601 offset time in Asia/Hong_Kong.
data.channelCodeStringAll channel/refcode eventsChannel code.
data.refcodeStringRefcode events onlyRefcode; null for other channel events.
data.commissionPathStringAllFixed as /api/r25/channel-distribution/commission.

10.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:

FieldTypeApplicable eventsDescription
eventTypeStringAllSpecific Rebate event type.
occurredAtStringAllISO 8601 offset time in Asia/Hong_Kong.
data.channelCodeStringCHANNEL_REBATE_RATE_CHANGEDChannel code; null in Vault distribution plan events.
data.vaultAddressStringAllVault contract address.
data.commissionPathStringAllFixed as /api/r25/channel-distribution/commission.

10.5 Delivery Success, Timeouts, and Retries​

  • Any HTTP 2xx returned 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, and 410 immediately 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-Id for idempotent processing and return 2xx as quickly as possible.

11. Integration Notes and Current Limitations​

  1. The vaultAddress of /api/r25/standard-vault/metadata is required by the API contract; a missing, blank, or unknown address returns -1010.
  2. All response fields documented here are included; fields with no available value are returned as null.
  3. 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.
  4. The HTTP status of business responses remains 200; you must check code in the response JSON.
  5. 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), and X-Delivery-Id to protect the receiver with idempotency.
  6. 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.