Download OpenAPI specification:
This document describes usage of the VNX Platform Trading API that allows minting, burning and trading of VNX coins in an automated manner. Our API is organized into publicly accessible endpoints (trading pairs, quotes) which require authentication with a public key only, and private authenticated endpoints (balance, trading) which require requests to be signed with a private key. You can generate API keys in the My Account section on the VNX Platform.
Request payloads are form-encoded (Content-Type: application/x-www-form-urlencoded) or JSON (Content-Type: application/json), and all requests must specify a User-Agent header.
Responses are JSON encoded and differ for accepted(received) and error responses. The accepted response contains keys specific to a particular request and possibly an error key in case of business level error (reject)
{
"timestamp": "2021-03-22T17:18:03Z",
"OrdId": 1,
"OrdStatus": "Filled"
}
{
"timestamp": "2021-03-22T17:18:03Z",
"ordId": 2,
"ordStatus": "Rejected",
"error": {
"code": "limit_too_far_from_market_price",
"message": "The limit price is too far from the market price"
}
}
The error response has HTTP status other than Ok and contains the key error with subkeys: code, status, message.
{
"code": "invalid_nonce",
"status": 400,
"message": "Invalid nonce"
}
An ECDSA256 public-private keys pair is required to access the authenticated endpoints, you can generate the keys in the My Account section on the VNX Platform
CAUTION Never share your private key with anyone, it should only be used to generate the
x-app-signed-datasignature for your request
Authenticated requests must include x-app-public-key, x-app-signed-data and x-app-nonce HTTP headers.
The nonce. Nonce must be an always increasing, unsigned 64-bit integer, unique for each request that is made with a particular Public key. While a simple counter starting from 1 would provide a valid nonce, a more usual method of generating a valid nonce is to use a UNIX timestamp in milliseconds.
NOTE There is no way to reset the nonce for a
Public keyto a lower value, so be sure to use a nonce generation method that won't produce numbers less than the previous nonce. Too many requests with invalid nonces can result in temporary bans. Problems can arise from requests arriving out of order due to Public keys being shared across processes, or from system clock drift/recalibration.
The Public key of your key pair
Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
Sign of (URI path + POST data + nonce) with private key and convert it to base64url
The code snippet for generating the signature in Node.js follows below.
const crypto = require('crypto');
/** Sign Data
*
* @param {string} path - URL of the request endpoint starting with /api, e.g. /api/v1/private/queryOrders
* @param {object} request - JSON object with all parameters and their values, e.g. {symbol:"VCHF/CHF"}
* @param {number} nonce - unique always increasing positive integer number, e.g. UNIX timestamp in milliseconds
* @param {string} pk64 - base64 encoded private key in PEM format
*/
signData(path, request, nonce, pk64) {
// Create private key object
let pk = Buffer.from(pk64, 'base64').toString();
const sortedRequest = sortObjectDeep(request);
const data = path + JSON.stringify(sortedRequest) + String(nonce);
const signer = crypto.createSign('sha256');
signer.update(data);
signer.end();
// Create signature
const signature = signer.sign(pk);
// Convert signature to Base64url
const signatureBase64url = signature.toString('base64');
return signatureBase64url;
}
Request body (POST data) must be serialized into canonical JSON with recursive lexicographic key ordering. The code snippet for sortObjectDeep method in Node.js follows below.
/**
* Recursively sorts object keys in lexicographic order to produce a canonical JSON structure.
*
* Request body must be serialized into canonical JSON with recursive lexicographic key ordering.
*
* This function:
* - Sorts keys of plain objects (`{}`) at all nesting levels
* - Preserves array order (does NOT sort arrays, only processes their elements)
* - Leaves primitive values (string, number, boolean, null) unchanged
* - Ignores non-plain objects (Date, Buffer, class instances, etc.)
*
* The resulting object can be safely passed to `JSON.stringify()` to produce
* a deterministic and stable string representation for cryptographic signing.
*
* @param {*} value - Any JSON-serializable value (object, array, primitive)
* @returns {*} New value with all object keys sorted recursively
*
*/
function sortObjectDeep(value) {
if (Array.isArray(value)) {
return value.map(sortObjectDeep);
}
if (value && typeof value === 'object' && value.constructor === Object) {
const sorted = {};
Object.keys(value)
.sort()
.forEach((key) => {
sorted[key] = sortObjectDeep(value[key]);
});
return sorted;
}
return value;
}
We have various safeguards in place to protect against system abuse, DDoS attacks, etc. For REST API requests, these are broadly organised into request limits specific to the REST API.
NOTE (Temporary) Maximum 1 request per 1 sec for a particular
Public key.
Get the name and the version of this API, you can call it to be sure that you specified the correct host and that the Trading API service is up and running on this host.
{- "error": {
- "code": "invalid_request_limit",
- "status": 400,
- "message": "Invalid request limit"
}
}Get information about the assets that are available for deposit, withdrawal and minting. Asset information includes the list of supported blockchains for each asset
{- "timestamp": "2019-08-24T14:15:22Z",
- "assets": [
- {
- "asset": "VCHF",
- "units": [
- "1000"
], - "blockchains": [
- {
- "blockchain": "ETH",
- "isactive": true,
- "ismintallowed": true
}
]
}
]
}Get information about tradable pairs including status, fee schedules and order size limitations.
| status | string Enum: "online" "halted" Optionally filter output by the Trading pairs status |
{- "timestamp": "2019-08-24T14:15:22Z",
- "pairs": [
- {
- "pair": "VNXAU/BTC",
- "status": "online",
- "min_order_size": 0.1,
- "max_order_size": 0.1,
- "qty_decimals": 0,
- "fees_sell": {
- "Gold tier": [
- [
- 1000,
- 5
], - [
- -1,
- 2.5
]
], - "Basic tier": [
- [
- -1,
- 10
]
]
}, - "fees_buy": {
- "Gold tier": [
- [
- 1000,
- 5
], - [
- -1,
- 2.5
]
], - "Basic tier": [
- [
- -1,
- 10
]
]
}, - "fee_volume_currency": "string",
- "network_fee_sell": 0.1,
- "network_fee_sell_currency": "string",
- "network_fee_buy": 0.1,
- "network_fee_buy_currency": "string"
}
]
}Get current bid, ask and last prices and available liquidity for each trading pair (symbol).
| symbols | Array of strings Optionally filter output by the list of trading pairs (symbols) as base/quoted currency |
{- "timestamp": "2019-08-24T14:15:22Z",
- "quotes": [
- {
- "symbol": "VCHF/CHF",
- "a": [
- 0.1,
- 0.1
], - "b": [
- 0.1,
- 0.1
], - "c": 0.1,
- "upd": "2019-08-24T14:15:22Z",
- "mint": [
- {
- "unit": "1000",
- "i": [
- 0.1
], - "r": [
- 0.1
]
}
]
}
]
}Below you can find the endpoints that require requests to be signed with a private key.
Get available balances for each asset you have in your account on the VNX Platform.
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
{- "timestamp": "2019-08-24T14:15:22Z",
- "balances": [
- {
- "asset": "VNXAU",
- "available_balance": 0.1
}
]
}Place a new order with given parameters
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| timestamp required | string <date-time> Request date-time |
| clordid required | string User specified unique order reference |
| symbol required | string Trading pair (symbol) as base/quoted currency, for example VNXAU/BTC |
| side required | string Enum: "Buy" "Sell" Order direction (Buy/Sell) |
| ordtype required | string Value: "Limit" Order type (Limit only) |
| timeinforce required | string Value: "FOK" Order time in force (Fill or Kill only) |
| orderqty required | number <float> Order quantity with maximum decimal places from Trading pair attribute 'qty_decimals' |
| price required | number <float> Limit price |
{- "timestamp": "2019-08-24T14:15:22Z",
- "result": "success",
- "order": {
- "clordid": "string",
- "ordid": 0,
- "ordstatus": "Filled",
- "bought": 0.1,
- "bought_currency": "string",
- "sold": 0.1,
- "sold_currency": "string",
- "fee": 0.1,
- "fee_currency": "string"
}, - "error": {
- "code": "string",
- "message": "string"
}
}Query the history of orders
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| symbol | string Optionally filter output by this trading pair (symbol) as base/quoted currency, for example VNXAU/BTC |
| clordid | string Optionally filter output by this user specified unique order reference |
| date | string Optionally filter output by this date, format "YYYY-MM-DD" |
| limit | number <integer> Maximum number of orders to be returned. Default 50 if not specified |
{- "timestamp": "2019-08-24T14:15:22Z",
- "orders": [
- {
- "ordid": 0,
- "ordstatus": "Filled",
- "created": "2019-08-24T14:15:22Z",
- "clordid": "string",
- "symbol": "VNXAU/BTC",
- "side": "Buy",
- "ordtype": "Limit",
- "timeinforce": "FOK",
- "orderqty": 0.1,
- "price": 0.1,
- "rejreason": "non_marketable_fok_limit_price"
}
]
}Query the history of trades
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| symbol | string Optionally filter output by this trading pair (symbol) as base/quoted currency, for example VNXAU/BTC |
| clordid | string Optionally filter output by this user specified unique order reference |
| date | string Optionally filter output by this date, format "YYYY-MM-DD" |
| limit | number <integer> Maximum number of trades to be returned. Default 50 if not specified |
{- "timestamp": "2019-08-24T14:15:22Z",
- "trades": [
- {
- "tradeid": 0,
- "ordid": 0,
- "clordid": "string",
- "created": "2019-08-24T14:15:22Z",
- "symbol": "VNXAU/BTC",
- "side": "Buy",
- "tradeqty": 0.1,
- "price": 0.1,
- "fee": 0.1,
- "fee_currency": "string"
}
]
}Query the history of mint and burn requests
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| asset | string Optionally filter output by this asset, for example VNXAU |
| requestid | string Optionally filter output by this unique mint/burn request reference |
| date | string Optionally filter output by this date, format "YYYY-MM-DD" |
| limit | number <integer> Maximum number of requests to be returned. Default 50 if not specified |
{- "asset": "VNXAU",
- "requestid": "string",
- "date": "2024-09-12",
- "limit": 0
}{- "timestamp": "2019-08-24T14:15:22Z",
- "requests": [
- {
- "requestid": 123,
- "created": "2019-08-24T14:15:22Z",
- "status": "active",
- "type": "mint",
- "asset": "VNXAU",
- "blockchain": "ETH",
- "currency": "EUR",
- "quantity": 1,
- "unit": "1000",
- "price": 123.45,
- "txid": 123,
- "fee": 0.1,
- "spent": 100,
- "received": 100
}
]
}Get deposit address for a particular asset and blockchain
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| asset | string Asset being deposited, for example VCHF |
| blockchain | string Blockchain code, for example ETH |
{- "timestamp": "2019-08-24T14:15:22Z",
- "address": "0x7B0C15f39cD987A7d3F5D8D10B57ac6d633E9403",
- "dest_tag": 287166653,
- "minimum": "1"
}Get a list of withdrawal addresses
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| blockchain | string Optionally filter addresses for specific blockchain, for example ETH |
| destination | string Find the address by its Address label that is configured in your account |
{- "timestamp": "2019-08-24T14:15:22Z",
- "addresses": [
- {
- "destination": "AddrLabel",
- "blockchain": "ETH",
- "address": "0x7B0C15f39cD987A7d3F5D8D10B57ac6d633E9403",
- "memo": "Additional info",
- "dest_tag": 287166651,
- "status": "Confirmed"
}
]
}Make a withdrawal request
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| asset | string Asset being withdrawn, for example VCHF |
| quantity | number <float> Amout to be withdrawn |
| destination | string Address Label of a Withdrawal address, that is configured in your account |
| memo | string Optional memo for withdrawals on XLM blockchain |
| dest_tag | number <integer> Optional destination tag for withdrawals on XRP blockchain |
{- "timestamp": "2019-08-24T14:15:22Z",
- "txids": [
- 0
], - "fee": 0.5
}Mint a specified amount of an asset on a particular blockchain in exchange for the asset's base currency. For commodity assets, the payment currency and the maximum price must be specified in the request parameters
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| asset | string Asset to be minted, for example VCHF |
| blockchain | string Blockchain where the asset should be minted, for example ETH |
| quantity | number <integer> Mint quantity, specified in |
| price | number <float> Price in payment currency, required for commodity asset mint requests |
| unit | string Unit (Lot size or Metal bar size), required for commodity asset mint requests |
| currency | string Payment currency, required for commodity asset mint requests |
{- "timestamp": "2019-08-24T14:15:22Z",
- "txid": 123,
- "requestid": 321,
- "fee": 0.1,
- "spent": 100000,
- "spent_currency": "EUR"
}Burn a specified amount of an asset and receive asset's base currency. For commodity assets, the received currency and the minimum price must be specified in the request parameters
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| asset | string Asset to be burned, for example VEUR |
| quantity | number <integer> Burn quantity, specified in |
| price | number <float> Price in received currency, required for commodity asset burn requests |
| unit | string Unit (Lot size or Metal bar size), required for commodity asset burn requests |
| currency | string Received currency, required for commodity asset burn requests |
{- "timestamp": "2019-08-24T14:15:22Z",
- "txid": 123,
- "requestid": 321,
- "fee": 0.1,
- "received": 100000,
- "received_currency": "EUR"
}Below you can find the endpoints that require JSON (Content-Type: application/json) requests to be signed with a private key.
Add Fiat-to-Stablecoin rail (Pay-In) or Stablecoin-to-Fiat rail (Pay-Out) Fiat-to-Stablecoin rail automates conversion from the inbound fiat currency payment to the referenced stablecoin and withdrawal to the designated whitelisted wallet (destination). Stablecoin-to-Fiat rail automates conversion from the inbound stablecoin transfer to the referenced currency and payout to the provided destination bank account.
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| railtype required | string Enum: "FiatToStablecoin" "StablecoinToFiat" Payment Rail type (FiatToStablecoin/StablecoinToFiat) |
Sender party (object) or Sender wallets (object) Sender info | |
object Wallet info - mandatory for FiatToStablecoin rail | |
object Bank Account info - mandatory for StablecoinToFiat rail | |
object Payment instruction details to be transferred to a payment system | |
required | object Instructions info |
{- "railtype": "FiatToStablecoin",
- "sender": {
- "partyname": {
- "firstname": "string",
- "lastname": "string",
- "name": "string",
- "companyname": "string"
}, - "address": {
- "country": "string",
- "postalcode": "string",
- "city": "string",
- "state": "string",
- "street": "string",
- "buildingno": "string",
- "addressline1": "string",
- "addressline2": "string"
}, - "partytype": "Corporate"
}, - "wallet": {
- "destination": "string",
- "memo": "Additional info",
- "dest_tag": 287166653
}, - "bankaccount": {
- "destination": "string"
}, - "paymentdetails": {
- "paymentmethod": "string",
- "paymentrouting": "string"
}, - "instructions": {
- "asset": "VCHF",
- "currency": "EUR",
- "blockchain": "ETH"
}
}{- "railid": "3998dfdd-6e94-4387-9451-ebc0b64a2d7b",
- "status": "Pending",
- "reason": "Unavailable currency AED"
}Actual payment rail data is provided to a client by Query Request with optional filtering parameters
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| railid | string <uuid> Payment rail id (uuid) |
| railtype | string Enum: "FiatToStablecoin" "StablecoinToFiat" Payment Rail type (FiatToStablecoin/StablecoinToFiat) |
| status | string Enum: "Pending" "Rejected" "Active" "Deleted" Status of the new rail |
| date | string Optionally filter output by this date, format "YYYY-MM-DD" |
| limit | number <integer> Maximum number of requests to be returned. Default 50 if not specified |
{- "timestamp": "2019-08-24T14:15:22Z",
- "rails": [
- {
- "railid": "3998dfdd-6e94-4387-9451-ebc0b64a2d7b",
- "created": "2019-08-24T14:15:22Z",
- "railtype": "FiatToStablecoin",
- "status": "Pending",
- "reason": "Unavailable currency AED",
- "sender": {
- "partyname": {
- "firstname": "string",
- "lastname": "string",
- "name": "string",
- "companyname": "string"
}, - "address": {
- "country": "string",
- "postalcode": "string",
- "city": "string",
- "state": "string",
- "street": "string",
- "buildingno": "string",
- "addressline1": "string",
- "addressline2": "string"
}, - "partytype": "Corporate"
}, - "wallet": {
- "destination": "string",
- "memo": "Additional info",
- "dest_tag": 287166653
}, - "bankaccount": {
- "destination": "string"
}, - "paymentdetails": {
- "paymentmethod": "string",
- "paymentrouting": "string"
}, - "instructions": {
- "currency": "EUR",
- "blockchain": "ETH"
}
}
]
}Delete payment rail by rail id
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| railid required | string <uuid> Payment rail id (uuid) |
{- "railid": "3998dfdd-6e94-4387-9451-ebc0b64a2d7b"
}{- "railid": "4bdbda0a-03de-4557-a4a8-ac0325a035d9",
- "type": "FiatToStablecoin",
- "status": "Deleted",
- "created": "2026-05-27T15:47:42.389Z"
}Actual payments is provided to a client by Query Request with optional filtering parameters
| x-app-public-key | string The |
| x-app-nonce | integer <int64> Nonce must be an always increasing, unsigned 64-bit integer, for each request that is made with a particular |
| x-app-signed-data | string Encrypted signature of your message. Authenticated requests must be signed with a signature generated with your private key, nonce, payload, and URI path according to:
|
| id | string <uuid> Payment Id |
| providerid | string Provider payment Id |
| end2endid | string End to end Id |
| direction | string Enum: "In" "Out" Payment direction |
| status | string Enum: "Completed" "Rejected" "Processing" Payment status |
| railid | string <uuid> Payment rail id (uuid) |
| orderreference | string Order reference |
| valuedate | string or null <date> Value date |
{- "timestamp": "2019-08-24T14:15:22Z",
- "payments": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "providerid": "string",
- "end2endid": "string",
- "externalid": "string",
- "direction": "Out",
- "status": "Completed",
- "railid": "3998dfdd-6e94-4387-9451-ebc0b64a2d7b",
- "orderreference": "string",
- "valuedate": "2026-05-26",
- "result": { }
}
]
}