Skip to main content

Changelog

Changes to the partner API that integrators need to act on, newest first.

2026-11-09: Documentation brought in line with the API​

These pages now describe the partner API as it runs today. Many of the changes below shipped over the last months without being documented, so if your integration was built from earlier versions of these pages, review every item. The Postman collection was regenerated and covers every endpoint.

Authentication

  • A client has one live access token. Issuing a new token, with any grant, invalidates the previous one. Refresh tokens are single-use: a spent or superseded refresh token is refused with 400, code 10006. See Create a Token.
  • Client certificates are presented in the TLS handshake. The X-Client-Cert header is no longer accepted. See mTLS Client Certificates.
  • A call from outside the client's IP allow-list is refused with 401 (not 403).

Errors

  • Errors are {code, domain, message}, plus details on validation failures. The same code exists in several domains: identify an error by domain + code.
  • Most "not found" errors answer 400 with the area's own code, not 404. Each endpoint page lists its codes. See Errors.

Wallet and network are always chosen by the caller

  • Every operation that signs on-chain takes wallet_id, and network_id where it starts the operation: user buys (primary and secondary market), OTC and secondary-market sell, user burn, rent claim, user and node withdraw, setup creation, currency-token creation, KYC token and token recall. Cancel and delist sign with the wallet stored on the offer or listing. There is no fallback wallet.
  • Users no longer carry an address. Addresses live on wallets, and a user can hold several wallets, including more than one per chain.

Routes that moved or were removed

BeforeNow
/v2/admin/kyc/groups/**/v2/admin/kycs/{kyc_token_id}/groups/** (platform owner only)
/v2/admin/kyc/tokens/v2/admin/kyc-tokens
/v2/admin/kyc/nodes/{node_id}/addressesGET /v2/admin/nodes/{node_id}/kyc/addresses
POST /v2/admin/tokens/nodes/{node_id}/searchGET /v2/admin/tokens?node_id=…
POST /v2/users/tokens/searchGET /v2/users/tokens?node_id=…
GET /v2/admin/currency-tokens/activeGET /v2/admin/currency-tokens?is_active=true
/v2/admin/fees/owner, /fees/platform-owner/defaults, /fees/nodes/{node_id}/defaults, /fees/nodes/{node_id}/platform-owner/defaultsGET /v2/admin/fees?entity=…
/v2/admin/oracles/categories/{category_id}GET /v2/admin/oracles?category_id=…
POST /v2/admin/categories/{category_id}/children/searchGET /v2/admin/categories/{category_id}/children?page=…&per_page=…
/v2/admin/otc-order-rules/nodes/{node_id}[/tokens/{token_id}]GET /v2/admin/otc-order-rules?node_id=…&token_id=…
Node-scoped OTC listingsGET /v2/admin/otcs?node_id=…, GET /v2/admin/otcs/tokens/{token_id}
Node-level contract status and upgradePer setup: /v2/admin/nodes/{node_id}/setups/{setup_id}/contracts/…
PUT /v2/users/{user_id}/wallet, wallet address + signature updateRemoved. PATCH /v2/users/{user_id}/wallets/{wallet_id} only renames
/v2/users/{user_id}/wallets/{wallet_id}/currency-tokens/{currency_token_id}/v2/users/{user_id}/wallets/{wallet_id}/networks/{network_id}/assets/{asset_id}
/v2/blockchain/… chain catalogGET /v2/chains, GET /v2/networks
POST /v2/webhooksPOST /v2/webhooks/custodial (the old path is a deprecated alias)

Listings

  • Every listing is a GET with page and per_page (both required, per_page at most 100) and answers {data, total, page, per_page}. A filter that matches nothing answers an empty page.

Asynchronous operations

  • Token actions (listing, delist, passive, burn, rent, public transfer, open to OTC, open to secondary market), token and metric updates, currency-token deploy, mint and send, and OTC accept and cancel answer {"transaction_id": "…"} to poll. Token create answers 201 with {token_id, transaction_id}.
  • User burn and rent claim answer an empty 200; poll the user's transactions. Node withdraw answers null; poll the node's transactions.

Setups and contracts

  • A deploy starts with POST /v2/admin/nodes/{node_id}/setups (wallet_id and network_id required). Every call creates a new setup. POST …/setups/{setup_id}/deploy takes no body and only retries or resumes a deploy.

Tokens

  • Token create takes node_id, setup_id and network_id (the setup's network) in the body; the setup's wallet signs.
  • Token update and metric update write every field: an omitted number is stored as 0. Always send the complete set.

Currency tokens

  • Create takes node_id, network_id and wallet_id, deploys in the same call and answers 201 with the token in draft. /deploy only retries a failed deploy.

Fees

  • Fee percentages are strings with at most one decimal. Every write needs all nine values, takes its scope from the route, and answers 200 with the saved row. Setup-scoped fee endpoints, effective fees and the affected-setups count are new. See the fee overview.

User market operations

  • OTC and secondary-market sell take currency_token_id and unit_price instead of price_id and price_amount.
  • OTC cancel and secondary-market delist name the deal in the path (…/deals/{deal_id}/cancel, …/deals/{deal_id}/delist) and take no body.
  • New purchase quote endpoints answer the price breakdown before buying.

Chain data

  • GET /v2/blockchain/gas-fee now needs a token with node:summary:view and a network_id. It answers safe_gas_price, propose_gas_price and fast_gas_price instead of max_fee and max_priority_fee; the real-time gas_fee message changed the same way.
  • Analytics responses use camelCase field names.

Newly documented endpoints

Node setups and wallets, wallet assets, ownership-change processes, platform-owner wallets and settings, analytics, token deposits, rents, burn payouts, investors, retokenize and tokenization images, KYC tokens, setup-scoped fees, oracle CRUD, oracle metrics, category writes, custody / spot-quote / AI provider settings, user listing and wallets, purchase quotes, chains, networks and gas sponsor wallets.

2026-10-21: Monetary values are decimal strings​

Every monetary value in the partner API (/v2/admin/**, /v2/users/** and webhooks) is now a decimal string, such as "12.5". Field names and /v2 paths are unchanged. The rules, the error for a malformed value and examples are on Amounts and Percentages.

What changed

  • Price objects {id, amount, decimal, symbol, address}: amount (token token_price, total_value, salable_value, rental_income, …).
  • Token salable_percentage.
  • Fees: fee value percentages (0 to 100, at most one decimal, "2.5" = 2.5 %); fee amount and percentage in OTC, secondary-market and purchase breakdowns.
  • Prices: min_sell_price, max_sell_price, min_price, max_price, unit_price, price_amount.
  • OTC order rules: above_amount, below_amount, above_percent, below_percent.
  • Wallet summaries: balances and usd / try valuations.
  • Analytics volumes and fee revenue.
  • Currency tokens: total_supply; mint, send and withdraw amount. Node withdraw amount.
  • Purchase quotes: unit price, subtotal, total, seller proceeds.
  • Token-history start_value, end_value, rate; spot prices; gas fee quotes.

Whole-token counts (quantity, max_supply, listed_supply, sold_supply, purchased_supply, minimum and maximum purchase quantity), decimal, page, per_page, type, status and timestamps stay JSON numbers.

Transition policy

  • Responses return these fields as strings starting with this release, always in their shortest form ("12.5", never "12.50" or "1e-7"). If your client reads them as numbers, update it now.
  • Requests should send strings. For now, a JSON number is still accepted. Support for numbers ends in a later release. This changelog will announce the date at least 30 days in advance.
  • A malformed value, or a fee percentage with more than one decimal, is refused with HTTP 400 and code 10015 (invalid request payload). A details entry {field, message} names the rule.
  • Currency-token mint takes whole tokens. The SToken contract mints whole tokens, so a fractional amount such as "12.5" is now refused with 10015; before, it was accepted and the transaction completed without minting anything.
  • Secondary-market buy (/v2/users/**) buys a listing whole: quantity must equal the listing's quantity, and any other value is refused with HTTP 400, code 11004. The contract always transfers the whole listing; a different quantity used to be accepted and then approved the wrong payment.