NAV
python

Introduction

base = 'https://uat.sheeldmatch.com/api'

This document describes the REST API offered by Aplo.

The REST API allows market participants to access Aplo’s Prime Brokerage platform. All of our services and features are API-first: trading, data, custody, clearing, virtual accounts and back-office.

Market participants must test their connection using the User Acceptance Testing server before going to production.

Production server: https://sheeldmatch.com/api

UAT server: https://uat.sheeldmatch.com/api

Market participants must retrieve credentials from Aplo. Everyday, they also have to retrieve the instruments and venues information using the dedicated routes.

The payload of the requests will be a JSON object (see standard JSON specification) sent in the body of the request. Its structure will be described in this documentation, using the following data types:

Authentication

The REST API handles authentication through API keys.

Generate an API key

API keys can be created on a user basis. They are restricted to a role, a set of accounts and a set of IP addresses. A dedicated tab is available in the app by clicking on the user icon in the top right corner.

Authenticate each Request

Pass the X-API-Key header with each request:

import requests

api_key = 'bxaxSu64vYmkvTUl8IQd8gw7Wl0hfNGt'
headers = {'X-API-Key': api_key}
response = requests.get(endpoint, headers=headers)

Once done, market participants must design all trading API calls following the X-API-Key header authentication scheme. This scheme consists in a HTTP request with the X-API-Key header that contains your API key.

For example, the client has to include the following header in his requests:

X-API-Key: bxaxSu64vYmkvTUl8IQd8gw7Wl0hfNGt

Pagination

Some endpoints use pagination via these query parameters:

Parameter Allowed values Default value
page Any positive number 0
pageSize 5, 10, 25 or 50 10

Endpoints using pagination will always return a JSON object with the following schema:

{
  "data": [
    /* data object */
  ],
  "count": 34
}

With count being the total number of rows available for this endpoint.

Universe

Get Available Instruments

import requests

endpoint = '%s/instruments' % base
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve all instruments available for trading, alongside their name, ID and microstructures (trading rules).

To get the restricted list of instruments that your account has access to, see the assetUniverse property in the GET /user route accounts object.
You can trade an instrument if you have access to both the assetId and currencyId.

HTTP Request

GET /instruments

This endpoint doesn't require any parameters.

Response fields

Example of JSON structure returned by the request:

[
  {
    "date": "2010-01-01",
    "name": "BTC-USDT.SPOT",
    "iid": 1,
    "assetId": "BTC",
    "currencyId": "USDT",
    "lot": 2,
    "tick": 4,
    "availableForTrade": true,
    "availableForOTC": true,
    "asset": {
      "minWithdrawalAmount": "0.001",
      "rate": "67000.3",
      "id": "BTC",
      "name": "BTC",
      "description": "Bitcoin",
      "networkId": "e2f100f8-c549-5e44-a263-2e22dc21676d",
      "underlyingId": null,
      "currencyId": null,
      "issuingVenue": null,
      "marginId": null,
      "expiration": null,
      "strikePrice": null,
      "durationCode": null
    }
  }
]

The response is a JSON array of instruments with the following fields:

Field Type Description
date string Date of the current trading day
name string Aplo Instrument name
iid integer Aplo Instrument ID
assetId string Asset e.g. BTC, used for quantity
currencyId string Currency e.g. USDT, used for price
lot integer Maximum number of digits for the volume
tick integer Maximum number of digits for the price
availableForTrade boolean Is the instrument tradable from the Trade endpoint ?
availableForOTC boolean Is the instrument tradable from the OTC endpoint ?
asset json General information about the asset

Get Available Venues

import requests

endpoint = '%s/venues' % base
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve the venues available for trading.

HTTP Request

GET /venues

This request doesn't require any parameters.

Response fields

Example of JSON structure returned by the request:

[
  {
    "code": "1",
    "date": "2010-01-01",
    "vid": 1,
    "name": "SheeldMatch"
  },
  {
    "code": "B",
    "date": "2010-01-01",
    "vid": 2,
    "name": "Binance"
  }
]

The response is a JSON array of venues with the following fields :

Field Type Description
code string Aplo Venue code
date string Date of the current trading day
vid integer Aplo Venue ID
name string Venue name e.g. Binance

Get Available Assets

import requests

endpoint = '%s/assets' % base
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve ALL assets available in the Aplo universe.

To get the restricted list of assets that your account has access to, see the assetUniverse property in the GET /user route accounts object.

Assets have an automatically generated name based on their characteristics and the following schema:

{asset}-{currency}.{classification}-{margin}-{venue}-{durationCode}{expiration.format("YYMMDD")}-{strikePrice}

HTTP Request

GET /assets

This request doesn't require any parameters.

Response fields

Example of JSON structure returned by the request:

[
  {
    "id": "USD",
    "name": "USD",
    "description": "US Dollar",
    "minWithdrawalAmount": "100",
    "rate": "1",
    "classification": "S",
    "logo": "usd.svg",
    "availableProgramTrading": true,
    "underlyingId": null,
    "currencyId": null,
    "issuingVenue": null,
    "marginId": null,
    "expiration": null,
    "strikePrice": null,
    "durationCode": null
  },
  {
    "id": "wBTC_n",
    "name": "BTC-USDT.PERP-USDT-Binance2",
    "description": "Bitcoin Perpetual @ Binance2",
    "minWithdrawalAmount": "100000000",
    "rate": "36732.5",
    "classification": "W",
    "logo": "btc.svg",
    "availableProgramTrading": false,
    "underlyingId": "BTC",
    "currencyId": "USDT",
    "marginId": "USDT",
    "issuingVenue": "Binance2",
    "expiration": null,
    "durationCode": null,
    "strikePrice": null
  }
]

The response is a JSON array of venues with the following fields :

Field Type Description
id string Asset Id
name string Automatically computed asset name
description string Human readable name
minWithdrawalAmount string Minimum amount for a withdrawal request
rate string Current exchange rate (in USD)
classification string Internal classification for assets, can be "S" (Spot), "F" (Future), "T" (Test) or "W" (Perpetual)
logo string Internal logo name
availableProgramTrading boolean Whether this asset can be used for the program trading product
underlyingId string The underlying asset, null for Spot assets.
currencyId string The currency asset, null for Spot assets. Used to quote the contract
issuingVenue string The issuing Venue name (see the /venues route), null for Spot assets.
marginId string The margin asset, null for Spot assets. Used as collateral
expiration date The expiration date, null for Spot and Perpetual assets.
durationCode string The expiration duration code "W" (Week), "M" (Month), "Q" (Quarter) or "Y" (Year). Is null for Spot and Perpetual assets
strikePrice string The strike price for options (Call or Put) assets, null for Spot, Perpetual or Future assets

Get Available Networks

import requests

endpoint = '%s/networks' % base
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve the networks used in the Aplo universe.

HTTP Request

GET /networks

This request doesn't require any parameters.

Response fields

Example of JSON structure returned by the request:

[
  {
    "id": "FIAT",
    "name": "Fiat",
    "explorerUrl": null,
    "transferDuration": 0,
    "hasMemo": false,
    "assets": [
      {
        "minWithdrawalAmount": "100",
        "rate": "1",
        "strikePrice": null,
        "id": "USD",
        "name": "USD",
        "description": "US Dollar",
        "classification": "S",
        "logo": "usd.svg",
        "availableProgramTrading": true,
        "underlyingId": null,
        "currencyId": null,
        "issuingVenue": null,
        "marginId": null,
        "expiration": null,
        "durationCode": null,
        "withdrawalNetworkFees": "50"
      },
      {
        "minWithdrawalAmount": "50",
        "rate": "1.09037",
        "strikePrice": null,
        "id": "EUR",
        "name": "EUR",
        "description": "Euro",
        "classification": "S",
        "logo": "eur.svg",
        "availableProgramTrading": true,
        "underlyingId": null,
        "currencyId": null,
        "issuingVenue": null,
        "marginId": null,
        "expiration": null,
        "durationCode": null,
        "withdrawalNetworkFees": "50"
      }
    ]
  }
]

The response is a JSON array of venues with the following fields :

Field Type Description
id string Network Id
name string Human readable name
explorerUrl string Chain explorer URL (can be null)
transferDuration number Transfer duration of the network in seconds
hasMemo boolean Whether the network has the destination memo or tag feature
assets array List of assets available on this network (see the /assets route)

Trading

Usage guidelines

Aplo offers a low-latency and optimized trading environment. However, connections to external venues can sometimes increase the native latency and requests may timeout (especially posting Immediate-or-Cancel Routed orders).

For this reason, POST/PATCH/DELETE routes documented below can respond with the following:

case status message
success 200 Success
timeout 202 Request processing
error 400 See below for reason

Where the reason can be one of the following:

Virtual Account Trading

Users can pass orders for a specific virtual acccount using its unique Id, all routes described below may take an additional optional parameter:

Parameter Type Description
virtualAccountId number Specific virtual account passing the order

Token generation

import time

token = round(time.time() * 1000)

Market participants must provide unique tokens within a trading day to identify their orders.

Using unique tokens based on the current time in milliseconds is strongly recommended.

Order schema

An Order object is a JSON Object with the following schema:

{
  "mpid": "SHLD",
  "qid": "8912784723",
  "token": "123456789",
  "instrument": "BTC-USDT.SPOT",
  "venue": "SheeldMatch",
  "price": "11052.59",
  "volume": "15",
  "time": "2020-12-14T11:07:18.670Z",
  "closingTime": null,
  "initialDay": "2020-12-14",
  "day": "2020-12-14",
  "type": "Routed",
  "subType": "TWAP",
  "status": "received",
  "executedVolume": "0",
  "side": "B",
  "averagePrice": "0",
  "executionCount": 0,
  "assetId": "BTC",
  "currencyId": "USDT",
  "lot": 4,
  "tick": 2,
  "classification": "S",
  "requestedVolume": "20",
  "requestedPrice": "11055",
  "total": "221100",
  "virtualAccountId": null,
  "parameters": {
    "lifespan": "60"
  }
}
Field Type Description
mpid string 4-character Market participant ID as obtained from Aplo
qid integer A unique Quote ID provided by Aplo to identify the order
token string A token provided by the participant to uniquely identify the order
instrument string The Instrument Name
venue string The Venue Name
price string Quote price
volume string Quote size
time string ISO string date of order
closingTime string ISO string date of when the order was closed or null to indicate an order not closed yet
initialDay string ISO 8601 date of order opening
day string ISO 8601 date of last active session
type string deprecated Type of the order, can be "Auction", "Conditional", "Direct", "Lotted", "Pegged", "Routed" or "Scheduled"
subType string
"GTC", "IOC", "DAY", "POD", "FOK", "VIO", "TWAP", "VWAP", "IGO", "IDO", "ISO", "IPO", "MGO", "MDO", "MSO", "MPO", "SLO", "TPO", "VTO", "PTO", "LMT", "MKT" or "DCA"
status string Status of the order, can be "received", "open" or "closed"
executedVolume string The quote's executed volume
side string "B" (buy) or "S" (sell)
averagePrice string The quote's average price of execution
executionCount number The quote's number of execution
assetId string Asset name as retrieved using the instruments route
currencyId string Currency name as retrieved using the instruments route
classification string Can be "S" (spot), "F" (future), "T" (test) or "W" (perpetual swap)
requestedVolume string Initially requested volume when the order was created
requestedPrice string Initially requested price when the order was created
total string Total volume of currency traded for this Order
virtualAccountId number Virtual account id (null indicates the "Main Account")
parameters Object Optional parameters depending on the order subType (described below), can be empty.

parameters is an object with the following properties (based on subType)

Field Type Description
stop string Stop price of volume
lifespan number Lifespan for "TWAP" or "VWAP" orders, in minutes
priority string "price", "time" or "both", used for SOR (Smart Order Routing) orders
anchor string "mid", "bif", "offer" or "last", used for "SLO" or "TPO" orders
participation number Participation in percent, used for "VIO" orders

Request collateral locates

import requests

endpoint = '%s/participants/%s/orders/locates' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTCB99-USDT.PERP",
         "side": "buy",
         "volume": "15",
         "price": "11052.59"
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request a collateral locates when trading perpetual instruments.
It is advised to call this route before submitting an order to ensure the required collateral is available and deployed.

HTTP Request

POST /participants/:mpid/orders/locates

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route, the Instrument MUST be a Perpetual instrument
side string "buy" or "sell"
volume string Order size
price string Order price
virtualAccountId number optional Virtual account (main account if not provided)

Response fields

Success means the collateral is available and deployed.
The specific error reason Pending locates request means the collateral is being deployed by our services.

Subsequent calls using the same token as previously sent can be made to request an update on the collateral deployment.

Add a DMA Order

Direct market access (DMA) orders are executed instantly on a single exchange.
Here are the available DMA order types:

HTTP Request

POST /participants/:mpid/orders/dma/ioc
POST /participants/:mpid/orders/dma/day
POST /participants/:mpid/orders/dma/gtc POST /participants/:mpid/orders/dma/pod

import requests

endpoint = '%s/participants/%s/orders/dma/ioc' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59",
         "venue": "SheeldMatch"
       }
response = requests.post(endpoint, headers=headers, json=body)

All 3 endpoints require the same parameters:

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
venue string The Venue name as defined in the /venues route
virtualAccountId number optional Virtual account (main account if not provided)

Response

See Usage guidelines.

Add a SOR Order

Smart Order Routing (SOR) orders are working across several exchanges in order to optimise your execution to get the best price.
Here are the available SOR order types:

HTTP Request

POST /participants/:mpid/orders/sor/iso
POST /participants/:mpid/orders/sor/ido
POST /participants/:mpid/orders/sor/igo
POST /participants/:mpid/orders/sor/ipo

import requests

endpoint = '%s/participants/%s/orders/sor/iso' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59",
         "priority": "price"
       }
response = requests.post(endpoint, headers=headers, json=body)

All 3 endpoints require the same parameters:

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
priority string optional Can be "price", "time" or "both" (defaults to "both"), see below for details
virtualAccountId number optional Virtual account (main account if not provided)
Priority Description
"both" This is the preferred algorithm which strikes a good compromise between maximizing the fill ratio, minimizing the execution time and optimizing the fill price. It is used by default.
"price" This algorithm should be used when execution price is the most important criterion and fill ratio and speed of execution are secondary.
"time" This algorithm should be used when speed of execution is paramount.

Response

See Usage guidelines.

Add a DSA Order

Direct strategy access (DSA) orders are conductors, which are going to slice orders into smaller parcels of SOR orders, with the aim of minimising market impact, maximising execution price and fill rate. Here are the available DSA order types:

HTTP Request

POST /participants/:mpid/orders/dsa/vio

import requests

endpoint = '%s/participants/%s/orders/dsa/vio' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59",
         "participation": 15
       }
response = requests.post(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
participation integer Percentage of participation based on market average, must be an integer between 1 and 99
virtualAccountId number optional Virtual account (main account if not provided)

HTTP Request

POST /participants/:mpid/orders/dsa/twap
POST /participants/:mpid/orders/dsa/vwap

import requests

endpoint = '%s/participants/%s/orders/dsa/vwap' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59",
         "lifespan": 75
       }
response = requests.post(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
lifespan integer Lifespan of the order in minutes after its creation (limited to the current trading day closing time, if value exceeds it)
virtualAccountId number optional Virtual account (main account if not provided)

Response

See Usage guidelines.

Add a TMO Order

Tailor-made orders (TMO) designed to answer a client’s specific needs.
Here are the available TMO order types:

HTTP Request

POST /participants/:mpid/orders/tmo/pto

import requests

endpoint = '%s/participants/%s/orders/tmo/pto' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDC.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59"
       }
response = requests.post(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
virtualAccountId number optional Virtual account (main account if not provided)

HTTP Request

POST /participants/:mpid/orders/tmo/vto

import requests

endpoint = '%s/participants/%s/orders/tmo/vto' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59",
         "stop": "12003.4"
       }
response = requests.post(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
stop string Stop price for the order
virtualAccountId number optional Virtual account (main account if not provided)

HTTP Request

POST /participants/:mpid/orders/tmo/slo
POST /participants/:mpid/orders/tmo/tpo

import requests

endpoint = '%s/participants/%s/orders/tmo/tpo' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59",
         "stop": "12003.4",
         "anchor": "mid"
       }
response = requests.post(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy" or "sell"
volume string Order size
price string Order price
stop string Stop price for the order
anchor string optional "mid", "bid", "offer" or "last" (defaults to "last"), see below for details
virtualAccountId number optional Virtual account (main account if not provided)

The anchor specifies the condition to watch i.e. a price or a volume.

Anchor Descripton
"bid" Watch best bid
"last" Watch last execution
"offer" Watch best offer
"mid" Watch mid price

Response

See Usage guidelines.

Modify an Order

This method allows market participants to change the price and/or the size of an existing order.
If the modification is only a reduction of the order size, the order keeps its place in the price-level queue. Otherwise, the order goes back to the end of the queue.

HTTP Request

PATCH /participants/:mpid/orders/:token/modify

import requests

endpoint = '%s/participants/%s/orders/%s/modify' % (base, mpid, token)
body = {
         "volume": "9.5",
         "price": "16540",
         "instrument": "BTC-USDT.SPOT"
       }
response = requests.patch(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
instrument string Instrument Name as retrieved using the /instruments route
volume string Order size
price string Order price
virtualAccountId number optional Virtual account (main account if not provided)

Response

See Usage guidelines.

Reduce an Order

This method allows market participants to reduce the volume of an order without it going back to the end of the queue.
This method requires you provide a volume lower than the current ordered one.

HTTP Request

PATCH /participants/:mpid/orders/:token/reduce

import requests

endpoint = '%s/participants/%s/orders/%s/reduce' % (base, mpid, token)
body = {
         "volume": "9.5",
         "instrument": "BTC-USDT.SPOT"
       }
response = requests.patch(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
instrument string Instrument Name as retrieved using the /instruments route
volume string Order size
virtualAccountId number optional Virtual account (main account if not provided)

Response

See Usage guidelines.

Get Order Status

This method allows market participants to retrieve the status of a single order using its token and initialDay as identifier

HTTP Request

GET /participants/:mpid/orders/:token-:initialDay

Response fields

The response is an Order object.

Get Open Orders

This method allows market participants to retrieve all open orders for a Market Participant

HTTP Request

GET /participants/:mpid/orders/open

import requests

endpoint = '%s/participants/%s/orders/open' % (base, mpid)
response = requests.get(endpoint, headers=headers)

This route takes the following optional query parameters:

Parameter Type Description
virtualAccountId number Virtual account (main account if not provided)

Response fields

The response is a JSON array of Order objects

Get Orders

This method allows market participants to retrieve all orders for a Market Participant.

HTTP Request

GET /participants/:mpid/orders

import requests

endpoint = '%s/participants/%s/orders?page=%s&pageSize=%s&sort=%s|asc' % (base, mpid, page, pageSize, sortedColumn)
response = requests.get(endpoint, headers=headers)

This route takes the following optional query parameters:

Parameter Type Description
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
instrument string Instrument Name as retrieved using the /instruments route
side string "B" or "S"
hideClosed boolean Filters out unfilled closed orders, accepts "true" or "false" (defaults)
openOnly boolean Filters out all closed orders, accepts "true" or "false" (defaults)
virtualAccountId number Virtual account (main account if not provided)

Response fields

{
  "data": [
    /* Order object*/,
    ...
  ],
  "count": 15
}

Where data is a JSON array of Order objects

Cancel an Order

This method allows market participants to cancel one order

HTTP Request

DELETE /participants/:mpid/orders/:token

import requests

endpoint = '%s/participants/%s/orders/%s' % (base, mpid, token)
response = requests.delete(endpoint, headers=headers)

Response

See Usage guidelines.

Mass Cancel Orders

This method mass cancels all open orders of a Market Participant.

HTTP Request

DELETE /participants/:mpid/orders

import requests

endpoint = '%s/participants/%s/orders' % (base, mpid )
response = requests.delete(endpoint, headers=headers)

Response fields

No response

Suspend Trading

This method suspends a Market Participant. Its following trading messages will be rejected by the gateway.

HTTP Request

POST /participants/:mpid/suspend

import requests

endpoint = '%s/participants/%s/suspend' % (base, mpid )
response = requests.post(endpoint, headers=headers)

Response fields

No response

Resume Trading

This method resumes a Market Participant. Its following trading messages will be accepted by the gateway.

HTTP Request

POST /participants/:mpid/resume

import requests

endpoint = '%s/participants/%s/resume' % (base, mpid )
response = requests.post(endpoint, headers=headers)

Response fields

No response

Get collateral locates requests

This method allows market participants to retrieve all collateral locates requests made during the current session.

HTTP Request

GET /participants/:mpid/orders/locates-requests

import requests

endpoint = '%s/participants/%s/orders/locates-requests' % (base, mpid)
response = requests.get(endpoint, headers=headers)

Response fields

Example of JSON structure returned by the request:

[
  {
    "price": "0.458391",
    "volume": "2159728.2",
    "mpid": "SONE",
    "token": "2551884922255932",
    "time": "1661330566574000000",
    "iid": 19,
    "instrument": "BTC-USDT.PERP-Binance-USDT",
    "vid": 3,
    "venue": "Binance",
    "side": "S",
    "virtualAccountId": null,
    "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
    "day": "2022-08-24",
    "status": "completed",
    "id": "8f2752a0-4761-44b1-b3a0-da6affe06ffc",
    "createdAt": "2022-08-24T08:42:46.576Z",
    "updatedAt": "2022-08-24T12:26:15.008Z"
  },
  {
    "price": "0.459049",
    "volume": "214",
    "mpid": "SONE",
    "token": "2191275191699646",
    "time": "1661349149740000000",
    "iid": 19,
    "instrument": "BTC-USDT.PERP-Binance-USDT",
    "vid": 0,
    "venue": null,
    "side": "S",
    "virtualAccountId": null,
    "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
    "day": "2022-08-24",
    "status": "pending",
    "id": "5eb54c41-8717-4ea6-af2b-2174b63e674e",
    "createdAt": "2022-08-24T13:52:29.743Z",
    "updatedAt": "2022-08-24T13:52:29.743Z"
  }
]

The response is an array of JSON objects with the following fields:

Field Type Description
price string Price of the locates
volume string Volume of the locates
mpid string Market Participant Id
token string Unique token for this locates
time string Time of request (in nanoseconds)
iid number The Instrument ID for the given day
instrument string The Instrument name for the iid
vid number The Venue ID for the given day
venue string The Venue name for the vid (can be null for routed requests)
side string "B" or "S"
virtualAccountId number Virtual account id (can be null to indicate the "Main Account")
userId string Id of the User who made the request
day string Session of the locates
status string Status of the locates request, can be "pending", "processing", "completed", "rejected" or "error"
id string Unique Locates Id
createdAt string Date of creation
updatedAt string Date of last update

Submit a high touch ticket

This method allows market participant to submit new high-touch tickets for our trading desk.

HTTP Request

POST /accounts/:accountId/high-touch-tickets

import requests

endpoint = '%s/accounts/%s/high-touch-tickets' % (base, accountId)
body = {
  "stategy": "vwap",
  "startinTime": "2025-06-05T08:00:00.000Z",
  "endingTime": "null",
  "inputs": [
    {
      "assetId": "BTC",
      "quantity": "1.453"
    },
    {
      "assetId": "ADA",
      "quantity": "905"
    }
  ],
  "outputs": [
    {
      "assetId": "ETH",
      "proportion": "50"
    },
    {
      "assetId": "USDT",
      "proportion": "35"
    },
    {
      "assetId": "EURC",
      "proportion": "15"
    }
  ],
  "targetParticipant": "SONE"
}
response = requests.post(endpoint, headers=headers, json=body)

Body Parameters

Parameter Type Description
strategy string "implementationShortfall", "vwap", "twap", "inlinePov"
startingTime number or string Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
endingTime number or string Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ.
Required when strategy is either "vwap" or "twap", otherwise must be null
inputs Array Array of asset inputs (see below)
outputs Array Array of target outputs
participation number If strategy is inlinePov, must be a positive number with a maximum precision of 0.01 representing the market participation %. Otherwise, must be null
targetParticipant string The MPID where the outputs will be deposited on.
virtualAccountId number optional Virtual account id requesting the high-touch ticket (null indicates the "Main Account")

inputs is a JSON array of object with the following properties

Parameter Type Description
assetId string Asset Identifier
quantity number Quantity of asset
limitPrice number optional Limit price of the asset, can be null

outputs is a JSON array of object with the following properties

Parameter Type Description
assetId string Asset Identifier
proportion number Percentage of this asset in the resulting basket

Please note that inputs will source your "funding" account balances.
If need be, you must first transfer your funds back to the "funding" sub-account before submitting your High Touch ticket.

Response fields

Example of JSON structure returned by the request:

{
  "participation": "3",
  "attachments": [],
  "lowTouchOrderToken": null,
  "lowTouchOrderInitialDay": null,
  "id": "20250602A",
  "clientAccountId": "45cabb50-42f7-4a69-a534-db030882f34c",
  "clientVirtualAccountId": null,
  "clientMpid": "SONE",
  "mode": "preFunded",
  "strategy": "inlinePov",
  "status": "requested",
  "startingTime": "2025-05-30T16:00:00.618Z",
  "endingTime": null,
  "inputs": [
    { "assetId": "BTC", "quantity": "1.453", "limitPrice": null },
    { "assetId": "ADA", "quantity": "600", "limitPrice": null }
  ],
  "outputs": [
    { "assetId": "USDT", "proportion": "50" },
    { "assetId": "ETH", "proportion": "35" },
    { "assetId": "SOL", "proportion": "15" }
  ],
  "acquisitionDay": "2025-06-02",
  "publicNotes": null,
  "createdAt": "2025-06-02T14:01:55.522Z"
}

Backoffice

Get MPID Balances

import requests

endpoint = '%s/participants/%s/balances' % (base, mpid)
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve their balances.

HTTP Request

GET /participants/:MPID/balances

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve balances for

Response fields

Example of JSON structure returned by the request:

[
  {
    "quantity": "100",
    "borrowed": "0",
    "committed": "0",
    "collateralized": "0",
    "accumulated": "0",
    "cost": "4376041",
    "positionCost": "4376041",
    "entryPrice": "43760.41",
    "assetId": "BTC",
    "mpid": "SHLD",
    "virtualAccountId": null,
    "asset": {
      "minWithdrawalAmount": "0.01",
      "rate": "26933.62",
      "strikePrice": null,
      "id": "BTC",
      "name": "BTC",
      "description": "Bitcoin",
      "classification": "S",
      "logo": "btc.svg",
      "availableProgramTrading": true,
      "underlyingId": null,
      "currencyId": null,
      "issuingVenue": null,
      "marginId": null,
      "expiration": null,
      "durationCode": null
    }
  }
]

The response is a JSON object of balances:

Field Type Description
quantity string Balance
borrowed string Borrowed balance
committed string Committed balance
collateralized string Collateralized balance
accumulated string Accumulated transacted quantity of asset
cost string Money flow of asset
positionCost string Current position cost for this asset
entryPrice string PositionCost / quantity
assetId string Asset ASCII identifier
mpid string 4-character MPID
virtualAccountId number Virtual account id owning this balance (null indicates the "Main Account")
asset object Asset object (see the /assets route)

Get User Information

import requests

endpoint = '%s/user' % base
response = requests.get(endpoint, headers=headers)

This route allows users to retrive the detailed user data such as which market participants and accounts they have access to.

HTTP Request

GET /user

This endpoint doesn't require any parameters.

Response fields

Example of JSON structure returned by the request:

{
  "user": {
    "id": "ec4c98ee-c83e-42cf-9d23-0bcb367b1ef3",
    "email": "account@account.com",
    "firstname": "First",
    "lastname": "Last",
    "fullname": "First Last",
    "totpValidated": true,
    "tosUpdatedAt": "2020-01-01 00:00:00+00",
    "lastSigninAt": "2020-01-01 00:00:00+00",
    "defaultAccountId": "35a6934e-94e5-4396-94e6-a2b86bce6bf9",
    "defaultParticipantId": "SHLD",
    "cancelDisconnect": false,
    "createdAt": "2020-01-01 00:00:00+00"
  },
  "participants": {
    "SHLD": {
      "mpid": "SHLD",
      "accountId": "35a6934e-94e5-4396-94e6-a2b86bce6bf9",
      "maxRate": 1000,
      "maxVol": 1000000,
      "maxDailyVol": "1000000000",
      "maxOpen": 10000,
      "createdAt": "2020-01-01 00:00:00+00",
      "isSuspended": false,
      "isHalted": false
    }
  },
  "accounts": {
    "35a6934e-94e5-4396-94e6-a2b86bce6bf9": {
      "id": "35a6934e-94e5-4396-94e6-a2b86bce6bf9",
      "name": "Account1",
      "country": "FR",
      "role": {
        "id": "a61da8a1-c8e2-55aa-9858-f8436f569f93",
        "name": "admin",
        "createdAt": "2020-01-01 00:00:00+00"
      },
      "permissions": ["u_orders", "u_otc", "u_trading"],
      "assetUniverse": {
        "BTC": { "isActive": true },
        "ETH": { "isActive": true },
        "SOL": { "isActive": true },
        "EURC": { "isActive": true }
      }
    }
  }
}

The user property has the following fields:

Field Type Description
id string Account UUID
email string Account email
firstname string First name
lastname string Last name
fullname string First name + Last name
totpValidated boolean Is the TOTP 2FA validated ?
tosUpdatedAt string Date of acceptance of terms of service
defaultAccountId string Default Account UUID
defaultParticipantId string Default MPID used by the account
cancelDisconnect boolean Do we automatically cancel open orders on disconnection ?
createdAt string Date of account creation

The accounts property (indexed by account Ids) contains objects with the following fields:

Field Type Description
id string Account UUID
name string Account name
country string Account country, used for IP geolocation security
permissions Array Account permissions, used internally by Aplo to restrict feature/API access
assetUniverse Object The list of assets the account has access to.

The role property in each accounts contains the following fields:

Field Type Description
id string Role UUID
name string Role name
createdAt Date Role creation date

The participants property (indexed by MPIDs) contains objects with the following fields:

Field Type Description
mpid string 4-character Market participant ID
accountId string Account UUID
maxRate number Maximum number of messages per second
maxVol number Maximum USD notional value of an order
maxOpen number Maximum USD notional value of open orders
maxDailyVol string Maximum USD notional value of all orders in a day
createdAt string Date of creation of the participant
isSuspended boolean Whether or not this participant has been suspended by the user or not (trading cannot be done while suspended)
isHalted boolean Similar to isSuspended but is managed by Aplo directly. (trading cannot be done if halted)

Get Withdrawal Addresses

import requests

endpoint = '%s/accounts/%s/addresses' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allow users to get all available withdrawal address for their account (or a specific virtual account if given).

HTTP Request

GET /accounts/:accountId/addresses

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve withdrawal addresses for

Response fields

Example of JSON structure returned by the request:

[
  {
    "id": "314e8f4b-4948-4e2e-b4f0-12c7155c930f",
    "accountId": "2e530764-9228-437e-a62f-a049e6400269",
    "virtualAccountId": null,
    "isArchived": false,
    "isWhitelisted": true,
    "whitelistedAt": "2023-11-24T13:35:26.151Z",
    "whitelistValidators": [
      {
        "name": "User One",
        "time": 1659083710297,
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "approved": true
      }
    ],
    "name": "BTC deposit address",
    "networkId": "BTC",
    "isUniversal": true,
    "value": "98Dj-NLC86jd:42Lxzk9ld:9228",
    "memo": "0DJDZ",
    "isSelfBeneficiary": true,
    "beneficiaryLegalName": null,
    "beneficiaryFirstName": null,
    "beneficiaryLastName": null,
    "beneficiaryContactEmail": null,
    "beneficiaryCountry": null,
    "beneficiaryAddress": null,
    "beneficiaryActivity": null,
    "beneficiaryTaxId": null,
    "beneficiaryRelationship": null,
    "paymentReason": null,
    "isSelfHosted": true,
    "providerName": null,
    "providerWebsite": null,
    "providerCountry": null,
    "walletPurpose": "testing",
    "description": null,
    "createdAt": "2023-11-24T13:35:26.151Z",
    "provider": null,
    "assets": [...]
  },
  {
    "id": "a14e8f4b-4948-4e2e-b4f0-1wc7155c9302",
    "accountId": "2e530764-9228-437e-a62f-a049e6400269",
    "virtualAccountId": 1138967864,
    "isArchived": false,
    "isWhitelisted": true,
    "whitelistedAt": "2023-11-24T13:35:26.151Z",
    "whitelistValidators": [
      {
        "name": "User One",
        "time": 1659083710297,
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "approved": true
      }
    ],
    "name": "BTC deposit address 1138967864",
    "networkId": "BTC",
    "isUniversal": false,
    "value": "98Dj-NLc86JD:42l2329LDQ:5143",
    "memo": null,
    "isSelfBeneficiary": false,
    "beneficiaryLegalName": "Company Name",
    "beneficiaryFirstName": null,
    "beneficiaryLastName": null,
    "beneficiaryContactEmail": "contact@company.com",
    "beneficiaryCountry": "FR",
    "beneficiaryAddress": "19 rue des ailerons bleutés, Paris",
    "beneficiaryActivity": null,
    "beneficiaryTaxId": null,
    "beneficiaryRelationship": "Intra-group transfer; Deposit",
    "paymentReason": "Intra-group",
    "isSelfHosted": false,
    "providerName": null,
    "providerWebsite": null,
    "providerCountry": null,
    "walletPurpose": null,
    "description": "BTC deposit address 1138967864",
    "createdAt": "2023-11-24T13:35:26.151Z",
    "provider": null,
    "assets": [...]
  },
  {
    "id": "c32a0065-aa65-4041-9656-63835159b4e4",
    "accountId": "2e530764-9228-437e-a62f-a049e6400269",
    "virtualAccountId": null,
    "isArchived": false,
    "isWhitelisted": true,
    "whitelistedAt": "2023-11-24T13:35:26.151Z",
    "whitelistValidators": [
      {
        "name": "User One",
        "time": 1659083710297,
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "approved": true
      }
    ],
    "name": "Withdrawal address Bitcoint",
    "networkId": "BTC",
    "isUniversal": false,
    "value": "98Dj-NLc86JD-42l2329LDQ25143",
    "memo": null,
    "isSelfBeneficiary": true,
    "beneficiaryLegalName": null,
    "beneficiaryFirstName": null,
    "beneficiaryLastName": null,
    "beneficiaryContactEmail": null,
    "beneficiaryCountry": null,
    "beneficiaryAddress": null,
    "beneficiaryActivity": null,
    "beneficiaryTaxId": null,
    "beneficiaryRelationship": null,
    "paymentReason": null,
    "isSelfHosted": false,
    "providerName": null,
    "providerWebsite": null,
    "providerCountry": null,
    "walletPurpose": null,
    "description": "BTC deposit address 1138967864",
    "createdAt": "2023-11-24T13:35:26.151Z",
    "provider": {
      "id": "41d8fb99-8f54-4f12-bfae-10e6abbcf807",
      "name": "Binance",
      "website": "https://www.binance.com/",
      "country": "SC"
    },
    "assets": [...]
  },
]

The response is an array of JSON objects with the following fields:

Header Type Description
id string Address unique ID
accountId string Address owner's account Id
virtualAccountId number The virtual account that this address is linked to (null indicates the "Main Account")
isArchived boolean Whether the address has been archived or not
isWhitelisted boolean Whether the address has been whitelisted.
whitelistedAt Date Date of whitelisting for this address, is null if the address is not whitelisted
whitelistValidators array Array of whitelisting validators (see below)
name string Human readable address alias
networkId string Network id (see /networks)
isUniversal boolean Whether the address is universal for all assets on the network
value string Actual address value
memo string Memo/Tag for this address (can be null)
isSelfBeneficiary boolean Whether this address's beneficiary is the account's owner or someone else
beneficiaryLegalName string The address beneficiary's legal name. Can be null if isSelfBeneficiary is true or if the beneficiary is a natural person.
beneficiaryFirstName string The address beneficiary's first name. Can be null if isSelfBeneficiary is true or if the beneficiary is a legal person.
beneficiaryLastName string The address beneficiary's last name. Can be null if isSelfBeneficiary is true or if the beneficiary is a legal person.
beneficiaryContactEmail string The address beneficiary's contact email (can be null)
beneficiaryCountry string The address beneficiary's country ISO code. Can be null if isSelfBeneficiary is true.
beneficiaryAddress string The address beneficiary's real life address (can be null)
beneficiaryActivity string The address beneficiary's business activity (can be null)
beneficiaryTaxId string The address beneficiary's tax ID (can be null)
beneficiaryRelationship string The address beneficiary's business relationship between the account's owner. Can be null if isSelfBeneficiary is true.
paymentReason string The reasons for payment to the address beneficiary. Can be null if isSelfBeneficiary is true.
isSelfHosted boolean Whether or not this address is self hosted or on a thrid party provider.
providerName string The address provider's name. Can be null if isSelfBeneficiary is false orisSelfHosted is true.
providerWebsite string The address provider's website. Can be null if isSelfBeneficiary is false orisSelfHosted is true.
providerCountry string The address provider's country ISO code. Can be null if isSelfBeneficiary is false orisSelfHosted is true.
walletPurpose string The purpose of the self hosted wallet. Can be null if isSelfBeneficiary is false or isSelfHosted is false.
description string Additional comments for this address (can be null)
createdAt Date Date of creation
provider object The address provider's information (see below). Can be null if isSelfBeneficiary is false or isSelfHosted is true
assets array List of supported assets that can be withdrawn on this address (see the /assets route)

provider is a JSON oject with the following properties:

Header Type Description
id string Address provider ID
name string The provider's name
website string The provider's website (can be null)
country string The provider's country ISO code (can be null)

whitelistValidators is an array of JSON object with the following properties:

Header Type Description
name string Full name of the validator
time number Timestamp of validation/rejection
userId string UUID of the validator
approved boolean Whether the validator approved the address' whitelisting or not

Address whitelisting is an optional account wide parameter. The number of validators needed to whitelist an address can be modified by our operations team.

Add a new withdrawal address

import requests

endpoint = '%s/accounts/%s/addresses' % (base, accountId)
body = {
    "virtualAccountId": null,
    "name":"New Bitcoin withdrawal address",
    "networkId":"BTC",
    "isUniversal": false,
    "assets": ["BTC"],
    "value":"98Dj-NLC86jd:42Lxzk9ldq:5143",
    "memo":"0DJDZ",
    "isSelfBeneficiary": true,
    "isProfessional": false,
    "beneficiaryLegalName": null,
    "beneficiaryFirstName": null,
    "beneficiaryLastName": null,
    "beneficiaryContactEmail": null,
    "beneficiaryCountry": null,
    "beneficiaryAddress": null,
    "beneficiaryActivity": null,
    "beneficiaryTaxId": null,
    "beneficiaryRelationship": null,
    "paymentReason": null,
    "isSelfHosted": true,
    "isOtherProvider": false,
    "providerId": null,
    "providerName": null,
    "providerWebsite": null,
    "providerCountry": null,
    "purpose": "Transfer",
    "description": "New Bitcoin withdrawal address",
}
response = requests.post(endpoint, headers=headers, json=body)

This route allow users to add a new withdrawal address.

HTTP Request

POST /accounts/:accountId/addresses

Body Parameters

Parameter Type Description
virtualAccountId number optional Virtual account id this address is for (null indicates the "Main Account")
name string Address alias
networkId string Network ID or name
isUniversal boolean Whether the address is universal for all assets on the network
assets array List of assets to be withdrawn on this address. mandatory if isUniversal is false.
value string Actual address value on the specified network
memo string optional Address memo
isSelfBeneficiary boolean Whether this address's beneficiary is the account's owner or someone else
isProfessional boolean Whether this address's beneficiary is a legal person or natural person. optional if isSelfBeneficiary is true
beneficiaryLegalName string The address beneficiary's legal name. optional if isSelfBeneficiary is true or isProfessional is false.
beneficiaryFirstName string The address beneficiary's first name. optional if isSelfBeneficiary is true or isProfessional is true.
beneficiaryLastName string The address beneficiary's last name. optional if isSelfBeneficiary is true or isProfessional is true.
beneficiaryContactEmail string optional The address beneficiary's contact email
beneficiaryCountry string The address beneficiary's country ISO code. optional if isSelfBeneficiary is true.
beneficiaryAddress string optional The address beneficiary's real life address
beneficiaryActivity string optional The address beneficiary's business activity
beneficiaryTaxId string optional The address beneficiary's tax ID
beneficiaryRelationship string The address beneficiary's business relationship between the account's owner. optional if isSelfBeneficiary is true.
paymentReason string The reasons for payment to the address beneficiary. optional if isSelfBeneficiary is true.
isSelfHosted boolean Whether or not this address is self hosted or on a thrid party provider. optional if isSelfBeneficiary is false.
isOtherProvider boolean Whether or not you know your provider's ID. optional if isSelfBeneficiary is false or if isSelfHosted is true.
providerId string The address provider's ID. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is true.
providerName string The address provider's name. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is false.
providerWebsite string The address provider's website. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is false.
providerCountry string The address provider's country ISO code. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is false.
walletPurpose string The purpose of the self hosted wallet. optional if isSelfBeneficiary is false or if isSelfHosted is false.
description string optional Additional comments for this address

Response fields

See this route for details about the returned body.

Approve the whitelisting of a withdrawal address

import requests

endpoint = '%s/accounts/%s/addresses/%s/approve' % (base, accountId, addressId)
body = {
   "approved": true,
}
response = requests.patch(endpoint, headers=headers, json=body)

This route allow users to approve or reject the whitelisting process of a withdrawal address.

HTTP Request

PATCH /accounts/:accountId/addresses/:addressId/approve

Body Parameters

Parameter Type Description
approve boolean Whether to approve or reject the whitelisting of the address

Response fields

See this route for details about the returned body.

Modify a withdrawal address

import requests

endpoint = '%s/accounts/%s/addresses/%s' % (base, accountId, addressId)
body = {
    "isArchived": false,
    "name": "New Bitcoin withdrawal address",
    "isUniversal": false,
    "assets": ["BTC"],
    "isSelfBeneficiary": true,
    "isProfessional": false,
    "beneficiaryLegalName": null,
    "beneficiaryFirstName": null,
    "beneficiaryLastName": null,
    "beneficiaryContactEmail": null,
    "beneficiaryCountry": null,
    "beneficiaryAddress": null,
    "beneficiaryActivity": null,
    "beneficiaryTaxId": null,
    "beneficiaryRelationship": null,
    "paymentReason": null,
    "isSelfHosted": true,
    "isOtherProvider": false,
    "providerId": null,
    "providerName": null,
    "providerWebsite": null,
    "providerCountry": null,
    "purpose": "Transfer",
    "description": null,
}
response = requests.patch(endpoint, headers=headers, json=body)

This route allow users to modify a withdrawal address.

HTTP Request

PATCH /accounts/:accountId/addresses/:addressId

Body Parameters

Parameter Type Description
isArchived boolean optional Whether or not the address is usable for withdrawals
name string optional Address alias
isUniversal boolean optional Whether the address is universal for all assets on the network
assets array List of assets to be withdrawn on this address. mandatory if isUniversal is false.
isSelfBeneficiary boolean optional Whether this address's beneficiary is the account's owner or someone else
isProfessional boolean Whether this address's beneficiary is a legal person or natural person. optional if isSelfBeneficiary is true
beneficiaryLegalName string The address beneficiary's legal name. optional if isSelfBeneficiary is true or isProfessional is false.
beneficiaryFirstName string The address beneficiary's first name. optional if isSelfBeneficiary is true or isProfessional is true.
beneficiaryLastName string The address beneficiary's last name. optional if isSelfBeneficiary is true or isProfessional is true.
beneficiaryContactEmail string optional The address beneficiary's contact email
beneficiaryCountry string The address beneficiary's country ISO code. optional if isSelfBeneficiary is true.
beneficiaryAddress string optional The address beneficiary's real life address
beneficiaryActivity string optional The address beneficiary's business activity
beneficiaryTaxId string optional The address beneficiary's tax ID
beneficiaryRelationship string The address beneficiary's business relationship between the account's owner. optional if isSelfBeneficiary is true.
paymentReason string The reasons for payment to the address beneficiary. optional if isSelfBeneficiary is true.
isSelfHosted boolean Whether or not this address is self hosted or on a thrid party provider. optional if isSelfBeneficiary is false.
isOtherProvider boolean Whether or not you know your provider's ID. optional if isSelfBeneficiary is false or if isSelfHosted is true.
providerId string The address provider's ID. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is true.
providerName string The address provider's name. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is false.
providerWebsite string The address provider's website. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is false.
providerCountry string The address provider's country ISO code. optional if isSelfBeneficiary is false or if isSelfHosted is true or if isOtherProvider is false.
walletPurpose string The purpose of the self hosted wallet. optional if isSelfBeneficiary is false or if isSelfHosted is false.
description string optional Additional comments for this address

Response fields

See this route for details about the returned body.

Update assets for a withdrawal address

import requests

endpoint = '%s/accounts/%s/addresses/%s/assets' % (base, accountId, addressId)
body = {
  "assets": [
    "USDT",
    "UDSC"
  ]
}
response = requests.put(endpoint, headers=headers, json=body)

This route allow users to update all assets for a withdrawal address, making it possible for the specified assets to be withdrawn on this address.

The provided assets must be available on the network the address uses.

HTTP Request

PUT /accounts/:accountId/addresses/:addressId/assets

Get Withdrawal Banks

import requests

endpoint = '%s/accounts/%s/banks' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allow users to get all available withdrawal bank accounts for their account (or a specific virtual account if given).

HTTP Request

GET /accounts/:accountId/banks

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve withdrawal banks for

Response fields

Example of JSON structure returned by the request:

[
  {
    "id": "a3c9c401-2b3e-4741-8d93-10075958fb2f",
    "description": "Withdrawal Bank account SEPA",
    "beneficiaryName": "SheeldTrading 1",
    "beneficiaryAddress1": "15 rue des Allités",
    "beneficiaryAddress2": null,
    "beneficiaryPostcode": "75001",
    "beneficiaryCity": "Paris",
    "beneficiaryRegion": null,
    "beneficiaryCountry": "FR",
    "bankName": "NEO PAYMENT FACTORY S.L.",
    "bankAddress1": "C. Comte Urgell 143",
    "bankAddress2": null,
    "bankPostcode": "31000",
    "bankCity": "Toulouse",
    "bankRegion": null,
    "bankCountry": "FR",
    "bankId": "ZH02CITI00001077181611",
    "bankAccountNumber": "98DNQ",
    "isIntermediary": false,
    "intermediaryBankId": null,
    "walletAddress": null,
    "isApprovedByAplo": true,
    "isWhitelisted": true,
    "whitelistedAt": "2021-12-31T23:00:00.000Z",
    "whitelistValidators": [
      {
        "name": "User One",
        "time": 1659083710297,
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "approved": true
      }
    ],
    "isArchived": false,
    "isActive": true,
    "networkId": "SEPA",
    "accountId": "2e530764-9228-437e-a62f-a049e6400269",
    "virtualAccountId": null,
    "createdAt": "2022-12-15T10:38:02.575Z",
    "assetId": "EUR"
  },
  {
    "id": "c2d16c3d-3d05-4c8f-b8ef-5495f3eb506f",
    "description": "Withdrawal Bank account BLINC",
    "beneficiaryName": "SheeldTrading 1",
    "beneficiaryAddress1": null,
    "beneficiaryAddress2": null,
    "beneficiaryPostcode": null,
    "beneficiaryCity": null,
    "beneficiaryRegion": null,
    "beneficiaryCountry": null,
    "bankName": null,
    "bankAddress1": null,
    "bankAddress2": null,
    "bankPostcode": null,
    "bankCity": null,
    "bankRegion": null,
    "bankCountry": null,
    "bankId": null,
    "bankAccountNumber": null,
    "isIntermediary": false,
    "intermediaryBankId": null,
    "walletAddress": "97DNQZQOZDZQ",
    "isApprovedByAplo": true,
    "isWhitelisted": true,
    "whitelistedAt": "2021-12-31T23:00:00.000Z",
    "whitelistValidators": [
      {
        "name": "User One",
        "time": 1659083710297,
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "approved": true
      }
    ],
    "isArchived": false,
    "isActive": true,
    "networkId": "BLINC",
    "accountId": "2e530764-9228-437e-a62f-a049e6400269",
    "virtualAccountId": null,
    "createdAt": "2022-12-15T10:38:02.575Z",
    "assetId": "USD"
  }
]

The response is an array of JSON objects with the following fields:

Header Type Description
id string Aplo Bank unique ID
networkId string Network id (see /networks)
beneficiaryName string The name of the bank account's beneficiary (can be null depending on the network used)
beneficiaryAddress1 string The first address line of the bank account's beneficiary (can be null depending on the network used)
beneficiaryAddress2 string The second address line of the bank account's beneficiary (can be null depending on the network used)
beneficiaryPostcode string The postcode of the bank account's beneficiary (can be null depending on the network used)
beneficiaryCity string The city of the bank account's beneficiary (can be null depending on the network used)
beneficiaryRegion string The state/region of the bank account's beneficiary (can be null depending on the network used)
beneficiaryCountry string The country of the bank account's beneficiary (can be null depending on the network used)
bankName string The name of the bank account (can be null depending on the network used)
bankAddress1 string The first address line of the bank account (can be null depending on the network used)
bankAddress2 string The second address of the bank account (can be null depending on the network used)
bankPostcode string The postcode of the bank account (can be null depending on the network used)
bankCity string The city of the bank account (can be null depending on the network used)
bankRegion string The state/region of the bank account (can be null depending on the network used)
bankCountry string The country of the bank account (can be null depending on the network used)
bankId string BIC/SWIFT code for "SEPA" and "SWIFT" networks, ABA routing number for "WIRE" network (can be null depending on the network used)
bankAccountNumber string IBAN for "SEPA", "SWIFT" and "WIRE" networks, can also be Account number for "WIRE" (can be null depending on the network used)
isIntermediary boolean Whether this bank account uses an intermediary bank account
intermediaryBankId string The intermediary bank Id: BIC/SWIFT code for "SEPA" and "SWIFT" networks, ABA routing number for "WIRE" network (null if "isIntermediary" is false)
walletAddress string The wallet address of the bank account (only used for "BLINC" network)
description string Human readable name
accountId string The account Id
isActive boolean Whether the bank is active or not
isApprovedByAplo boolean Whether the bank has been verified with a mandatory test deposit
isArchived boolean Whether the bank has been archived or not
isWhitelisted boolean Whether the bank has been whitelisted.
virtualAccountId number The virtual account that this bank is linked to (null indicates the "Main Account")
whitelistedAt Date Date of whitelisting for this bank, is null if the bank is not whitelisted
whitelistValidators array Array of whitelisting validators (see below)
assetId string The asset that can be withdrawn on this bank account
createdAt Date Date of creation

whitelistValidators is an array of JSON object with the following properties:

Header Type Description
name string Full name of the validator
time number Timestamp of validation/rejection
userId string UUID of the validator
approved boolean Whether the validator approved the bank's whitelisting or not

Bank whitelisting is an optional account wide parameter. The number of validators needed to witelist a bank can be modified by our operations team.

Add a new withdrawal bank

import requests

endpoint = '%s/accounts/%s/bank' % (base, accountId)
body = {
   "networkId": "SWIFT",
   "assetId": "EUR",
   "description": "Swift EUR withdrawal bank cc",
   "beneficiaryName": "SheeldTrading 1",
   "beneficiaryAddress1": "15 rue des Allités",
   "beneficiaryPostcode": "75001",
   "beneficiaryCity": "Paris",
   "beneficiaryCountry": "FR",
   "bankName": "NEO PAYMENT FACTORY S.L.",
   "bankAddress1": "C. Comte Urgell 143",
   "bankPostcode": "31000",
   "bankCity": "Toulouse",
   "bankCountry": "FR",
   "bankId": "ZH02CITI00001077181611",
   "bankAccountNumber": "98DNQ",
   "virtualAccountId": null,
}
response = requests.post(endpoint, headers=headers, json=body)

This route allow users to add a new withdrawal bank.

Allowed networks are: "SWIFT", "SEPA", "WIRE" and "BLINC".

"BLINC" banks only require two fields: "beneficiaryName" and "walletAddress". "SWIFT", "SEPA" and "WIRE" required fields are described below. Second address lines and state/regions are optional for bank and beneficiary in addition to the whole intermediary info.

HTTP Request

POST /accounts/:accountId/banks

Body Parameters

Parameter Type Description
networkId string Network ID or name
assetId string The asset to be withdrawn on this bank.
beneficiaryName string The name of the bank account's beneficiary (can be null depending on the network used)
beneficiaryAddress1 string The first address line of the bank account's beneficiary (can be null depending on the network used)
beneficiaryAddress2 string optional The second address line of the bank account's beneficiary (can be null depending on the network used)
beneficiaryPostcode string The postcode of the bank account's beneficiary (can be null depending on the network used)
beneficiaryCity string The city of the bank account's beneficiary (can be null depending on the network used)
beneficiaryRegion string optional The state/region of the bank account's beneficiary (can be null depending on the network used)
beneficiaryCountry string The country of the bank account's beneficiary (can be null depending on the network used)
bankName string The name of the bank account (can be null depending on the network used)
bankAddress1 string The first address line of the bank account (can be null depending on the network used)
bankAddress2 string optional The second address of the bank account (can be null depending on the network used)
bankPostcode string The postcode of the bank account (can be null depending on the network used)
bankCity string The city of the bank account (can be null depending on the network used)
bankRegion string optional The state/region of the bank account (can be null depending on the network used)
bankCountry string The country of the bank account (can be null depending on the network used)
bankId string BIC/SWIFT code for "SEPA" and "SWIFT" networks, ABA routing number for "WIRE" network (can be null depending on the network used)
bankAccountNumber string IBAN for "SEPA", "SWIFT" and "WIRE" networks, can also be Account number for "WIRE" (can be null depending on the network used)
isIntermediary boolean optional Whether this bank account uses an intermediary bank account
intermediaryBankId string optional The intermediary bank Id: BIC/SWIFT code for "SEPA" and "SWIFT" networks, ABA routing number for "WIRE" network (null if "isIntermediary" is false)
walletAddress string The wallet address of the bank account (only used for "BLINC" network)
description string Human readable name for this address
virtualAccountId number optional Virtual account id this address is for (null indicates the "Main Account")

Response fields

See this route for details about the returned body.

Approve the whitelisting of a bank account

import requests

endpoint = '%s/accounts/%s/banks/%s/approve' % (base, accountId, bankId)
body = {
   "approved": true,
}
response = requests.patch(endpoint, headers=headers, json=body)

This route allow users to approve or reject the whitelisting process of a bank account.

HTTP Request

PATCH /accounts/:accountId/banks/:bankId/approve

Body Parameters

Parameter Type Description
approve boolean Whether to approve or reject the whitelisting of the bank

Response fields

See this route for details about the returned body.

Modify a bank account

import requests

endpoint = '%s/accounts/%s/banks/%s' % (base, accountId, bankId)
body = {
   "description": "Actually I prefer this name"
   "isArchived": true,
}
response = requests.patch(endpoint, headers=headers)

This route allow users to modify a bank account.

HTTP Request

PATCH /accounts/:accountId/banks/:bankId

Body Parameters

Parameter Type Description
description string optional Human readable name for this bank account
isArchived boolean optional Whether or not the bank is usable for withdrawals

Response fields

See this route for details about the returned body.

Update assets for a bank account

import requests

endpoint = '%s/accounts/%s/banks/%s/assets' % (base, accountId, bankId)
body = {
  "assets": [
    "EUR",
  ]
}
response = requests.put(endpoint, headers=headers, json=body)

This route allow users to update all assets for a bank account, making it possible for the specified assets to be withdrawn on this bank account.

The provided assets must be available on the network the bank account uses.

HTTP Request

PUT /accounts/:accountId/banks/:bankId/assets

Get Internal Banks

import requests

endpoint = '%s/accounts/%s/banks/internal' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve Aplo's bank accounts for FIAT deposit and withdrawal purposes.

HTTP Request

GET /accounts/:accountId/banks/internal

Response fields

Example of JSON structure returned by the request:

[
  {
    "depositFixedFee": "5",
    "depositVariableFeeRate": "0.005",
    "depositMinFee": "10",
    "depositMaxFee": "40",
    "withdrawalFixedFee": "10",
    "withdrawalVariableFeeRate": "0.01",
    "withdrawalMinFee": "20",
    "withdrawalMaxFee": "100",
    "id": "2c83d612-38cf-457d-8a59-f3a56e108986",
    "description": "Deposit Bank account SEPA",
    "priority": 1,
    "countryWhitelist": "FR GB US",
    "countryBlacklist": null,
    "beneficiaryName": "Aplo",
    "beneficiaryAddress1": "15 rue des Allités",
    "beneficiaryAddress2": null,
    "beneficiaryPostcode": "75001",
    "beneficiaryCity": "Paris",
    "beneficiaryRegion": null,
    "beneficiaryCountry": "FR",
    "bankName": "NEO PAYMENT FACTORY S.L.",
    "bankAddress1": "C. Comte Urgell 143",
    "bankAddress2": null,
    "bankPostcode": "31000",
    "bankCity": "Toulouse",
    "bankRegion": null,
    "bankCountry": "FR",
    "bankId": "ZH02CITI00001077181611",
    "bankAccountNumber": "98DNQ",
    "isIntermediary": false,
    "intermediaryBankId": null,
    "walletAddress": null,
    "isActive": true,
    "networkId": "SEPA",
    "createdAt": "2025-07-02T22:00:00.000Z",
    "expectedTime": "2 days",
    "assetId": "EUR"
  }
]

The response is a JSON object with the following fields:

Field Type Description
depositFixedFee number Deposit fixed fee. Can be null.
depositVariableFeeRate number Deposit variable fee. Can be null.
depositMinFee number Deposit minimum fee. Can be null.
depositMaxFee number Deposit maximum fee. Can be null.
withdrawalFixedFee number Withdrawal fixed fee. Can be null.
withdrawalVariableFeeRate number Withdrawal variable fee. Can be null.
withdrawalMinFee number Withdrawal minimum fee. Can be null.
withdrawalMaxFee number Withdrawal maximum fee. Can be null.
id string UUID, used for FIAT withdrawals' sourceBankId
description string Human readable description.
priority number Used to determine which bank to use when sourceBankId is null for FIAT withdrawals.
countryWhitelist string Bank account country whitelist (overrides blacklist if set). Can be null.
countryBlacklist string Bank account country blacklist. Can be null.
beneficiaryName string The name of the bank account's beneficiary (can be null depending on the network used)
beneficiaryAddress1 string The first address line of the bank account's beneficiary (can be null depending on the network used)
beneficiaryAddress2 string The second address line of the bank account's beneficiary (can be null depending on the network used)
beneficiaryPostcode string The postcode of the bank account's beneficiary (can be null depending on the network used)
beneficiaryCity string The city of the bank account's beneficiary (can be null depending on the network used)
beneficiaryRegion string The state/region of the bank account's beneficiary (can be null depending on the network used)
beneficiaryCountry string The country of the bank account's beneficiary (can be null depending on the network used)
bankName string The name of the bank account (can be null depending on the network used)
bankAddress1 string The first address line of the bank account (can be null depending on the network used)
bankAddress2 string The second address of the bank account (can be null depending on the network used)
bankPostcode string The postcode of the bank account (can be null depending on the network used)
bankCity string The city of the bank account (can be null depending on the network used)
bankRegion string The state/region of the bank account (can be null depending on the network used)
bankCountry string The country of the bank account (can be null depending on the network used)
bankId string BIC/SWIFT code for "SEPA" and "SWIFT" networks, ABA routing number for "WIRE" network (can be null depending on the network used)
bankAccountNumber string IBAN for "SEPA", "SWIFT" and "WIRE" networks, can also be Account number for "WIRE" (can be null depending on the network used)
isIntermediary boolean Whether this bank account uses an intermediary bank account
intermediaryBankId string The intermediary bank Id: BIC/SWIFT code for "SEPA" and "SWIFT" networks, ABA routing number for "WIRE" network (null if "isIntermediary" is false)
walletAddress string The wallet address of the bank account (only used for "BLINC" network)
networkId string The bank network
createdAt date Creation date
expectedTime string Expected duration of payment processing
assetId string Asset supported by this bank

Get Deposit Destinations

import requests

endpoint = '%s/accounts/%s/deposit-destinations' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve the deposit addresses for the specified Account.

HTTP Request

GET /accounts/:accountId/deposit-destinations

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve destinations for

Response fields

Example of JSON structure returned by the request:

[
  {
    "minWithdrawalAmount": "1000",
    "rate": "0.3636",
    "strikePrice": null,
    "id": "XRP",
    "name": "XRP",
    "description": "Ripple",
    "classification": "S",
    "logo": "xrp.svg",
    "availableProgramTrading": true,
    "underlyingId": null,
    "currencyId": null,
    "issuingVenue": null,
    "marginId": null,
    "expiration": null,
    "durationCode": null,
    "internalAddresses": [
      {
        "id": "016bc6ed-20ef-4f89-9261-929c6204beab",
        "value": "fdb018e9-39c1-49b9-bbef-35029f67ea3c",
        "memo": null,
        "description": "Deposit address Ripple",
        "accountId": "2e530764-9228-437e-a62f-a049e6400269",
        "isActive": true,
        "virtualAccountId": null,
        "createdAt": "2022-12-15T10:38:02.575Z",
        "networkId": "XRP"
      }
    ]
  }
]

The response is a JSON object with the following fields:

Field Type Description
minWithdrawalAmount string Minimum amount to withdraw
rate string Current USD price of the asset
id string Asset ASCII id identifier
name string Asset ASCII name identifier
internalAddresses array Array of internal address object (see content below)

The internalAddresses, are an array of internal address object with the following properties:

Field Type Description
id string Internal address unique ID
networkId string Network id (see /networks)
value string Actual address value
description string Human readable name
memo string Memo/Tag for this address (can be null)
accountId string Address owner's account Id
virtualAccountId number The virtual account that this address is linked to (null indicates the "Main Account")
createdAt Date Date of creation

To get deposit info for FIAT assets, please refer to the GET internal banks route

Get Withdrawal Destinations

import requests

endpoint = '%s/accounts/%s/withdrawal-destinations' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allows market participants to retrieve the withdrawal addresses for the specified Account.

HTTP Request

GET /accounts/:accountId/withdrawal-destinations

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve destinations for

Response fields

Example of JSON structure returned by the request:

[
  {
    "minWithdrawalAmount": "1000",
    "rate": "0.3636",
    "strikePrice": null,
    "id": "XRP",
    "name": "XRP",
    "description": "Ripple",
    "classification": "S",
    "logo": "xrp.svg",
    "availableProgramTrading": true,
    "underlyingId": null,
    "currencyId": null,
    "issuingVenue": null,
    "marginId": null,
    "expiration": null,
    "durationCode": null,
    "externalAddresses": [
      {
        "id": "ab34bc89-fdd8-42d2-8f11-d20f3c0e8762",
        "value": "e8309358-483d-4d03-a953-c66318679add",
        "memo": null,
        "description": "Withdrawal address Bitcoin",
        "accountId": "2e530764-9228-437e-a62f-a049e6400269",
        "isActive": true,
        "isWhitelisted": true,
        "isArchived": false,
        "virtualAccountId": null,
        "whitelistedAt": "2022-07-29T08:35:10.297Z",
        "whitelistValidators": [
          {
            "name": "User One",
            "time": 1659083710297,
            "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
            "approved": true
          }
        ],
        "isSelfBeneficiary": false,
        "isSelfHosted": false,
        "beneficiaryCountry": null,
        "beneficiaryAddress": null,
        "beneficiaryRelationship": null,
        "walletPurpose": null,
        "providerName": null,
        "providerWebsite": null,
        "providerCountry": null,
        "createdAt": "2023-11-24T13:30:55.261Z",
        "whitelistingPolicy": null,
        "userId": null,
        "name": "Withdrawal address Bitcoin",
        "isUniversal": false,
        "providerId": null,
        "beneficiaryLegalName": null,
        "beneficiaryFirstName": null,
        "beneficiaryLastName": null,
        "paymentReason": null,
        "beneficiaryActivity": null,
        "beneficiaryTaxId": null,
        "beneficiaryContactEmail": null,
        "networkId": "BTC"
      }
    ],
    "externalBanks": [],
  },
  {
    "minWithdrawalAmount": "100",
    "rate": "1",
    "id": "USD",
    "name": "US Dollar",
    "externalAddresses": [],
    "externalBanks": [
      {
        "id": "17ddab40-34c1-451b-81bb-08fcadda384d",
        "description": "Withdrawal Bank account SWIFT",
        "beneficiaryName": "SheeldTrading 1",
        "beneficiaryAddress1": "15 rue des Allités",
        "beneficiaryAddress2": null,
        "beneficiaryPostcode": "75001",
        "beneficiaryCity": "Paris",
        "beneficiaryRegion": null,
        "beneficiaryCountry": "FR",
        "bankName": "NEO PAYMENT FACTORY S.L.",
        "bankAddress1": "C. Comte Urgell 143",
        "bankAddress2": null,
        "bankPostcode": "31000",
        "bankCity": "Toulouse",
        "bankRegion": null,
        "networkId": "SWIFT"
        ...
      },
      {
        "id": "c2d16c3d-3d05-4c8f-b8ef-5495f3eb506f",
        "description": "Withdrawal Bank account BLINC",
        "beneficiaryName": "SheeldTrading 1",
        "walletAddress": "97DNQZQOZDZQ",
        "networkId": "BLINC"
        ...
      }
    ],
  }
]

The response is a JSON object with the following fields:

Field Type Description
minWithdrawalAmount string Minimum amount to withdraw
rate string Current USD price of the asset
id string Asset ASCII id identifier
name string Asset ASCII name identifier
externalAddresses array Array of external address (see content below)
externalBanks array Array of withdrawal banks (see content below)

For externalAddresses, see the GET /address route.
For externalBanks, see the GET /banks route.

Request a crypto withdrawal

import requests

endpoint = '%s/accounts/%s/withdrawal-requests' % (base, accountId)
body = {
   "assetId": "BTC",
   "address": "98Dj-NLC86jd:42Lxzk9ldq:5143",
   "quantity": "100",
   "description": "My note",
   "includeFees": true,
   "virtualAccountId": null
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request a crypto withdrawal. The assets will be withdrawn from the Funding Account towards an external address.

HTTP Request

POST /accounts/:accountId/withdrawal-requests

Body Parameters

Parameter Type Description
assetId string Asset ID
address string Destination address value
memo string optional Destination address memo
networkId string optional Destination address network id
quantity string Withdrawal request volume
description string Custom note
includeFees boolean Whether fees are included in the quantity withdrawn or not
virtualAccountId number optional Virtual account id requesting the withdrawal (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "id": "87ccf43f-225e-4c77-9e32-7fdc4693e870",
  "assetId": "BTC",
  "destinationId": "732bb9f6-cca7-45da-aaef-225e5d79b81e",
  "destinationType": "externalAddress",
  "quantity": "100",
  "description": "My note",
  "accountId": "45cabb50-42f7-4a69-a534-db030882f34c",
  "status": "requested",
  "includeFees": true,
  "networkFeesQuantity": "0.1",
  "serviceFeesQuantity": "0.01",
  "networkFeesNotional": "5000",
  "serviceFeesNotional": "500",
  "virtualAccountId": null
}

The response is a JSON object with the following fields:

Field Type Description
id string Withdrawal request UUID
assetId string Asset ID
destinationId string Destination address UUID
destinationType string "extenralAddress"
quantity string Withdrawal request volume
description string Custom note
accountId string Account UUID
status string Withdrawal request status
virtualAccountId number Virtual account id (null indicates the "Main Account")
includeFees boolean Whether fees are included in the amount withdrawn
networkFeesQuantity number Network fees in kind. (used if includeFees is "true")
networkFeesNotional number Network fees in valuation currency. (used if includeFees is "false")
serviceFeesQuantity number Service fees in kind. (used if includeFees is "true")
serviceFeesNotional number Service fees in valuation currency. (used if includeFees is "false")

Request a BLINC withdrawal

import requests

endpoint = '%s/accounts/%s/withdrawal-requests' % (base, accountId)
body = {
   "assetId": "USD",
   "networkId": "BLINC",
   "walletAddress": "978DNQZ3FQKJ",
   "sourceBankId": "f48e40c0-aa41-56c4-9218-7f55b5ad6a11",
   "quantity": "100",
   "description": "My note",
   "includeFees": true,
   "virtualAccountId": null
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request a withdrawal on a "BLINC" bank account. The assets will be withdrawn from the Funding Account towards an external bank account.

It is possible to use your EURC balance to withdraw to a bank account that handles EUR. Same logic applies to USDC and USD.

HTTP Request

POST /accounts/:accountId/withdrawal-requests

Body Parameters

Parameter Type Description
assetId string Asset ID
walletAddress string Destination bank account walletAddress (as retrieved in the /banks route)
sourceBankId string Aplo's bank account the funds will be sent from. (as retrieved in the GET /banks/internal route). Can be null in which case, the source bank is chosen automatically.
networkId string "BLINC"
quantity string Withdrawal request volume
description string Custom note
includeFees boolean Whether fees are included in the quantity withdrawn or not
virtualAccountId number optional Virtual account id requesting the withdrawal (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "id": "a101e8b5-388f-56b3-ada7-29e2b2b464eb",
  "assetId": "USD",
  "conversionAssetId": "USDC",
  "destinationId": "3534296d-356b-5863-8db1-90ae3d833c3c",
  "destinationType": "externalBank",
  "quantity": "100000",
  "description": "My note",
  "accountId": "45cabb50-42f7-4a69-a534-db030882f34c",
  "status": "requested",
  "includeFees": true,
  "networkFeesQuantity": "0.1",
  "serviceFeesQuantity": "0.01",
  "networkFeesNotional": "5000",
  "serviceFeesNotional": "500",
  "virtualAccountId": null
}

The response is a JSON object with the following fields:

Field Type Description
id string Withdrawal request UUID
assetId string Asset ID
conversionAssetId string The asset that was converted to assetId before being withdrawn (USDC -> USD and EURC -> EUR), will be null for withdrawals without conversion
destinationId string Destination bank UUID
destinationType string "externalBank"
quantity string Withdrawal request volume
description string Custom note
accountId string Account UUID
status string Withdrawal request status
virtualAccountId number Virtual account id (null indicates the "Main Account")
includeFees boolean Whether fees are included in the amount withdrawn
networkFeesQuantity number Network fees in kind. (used if includeFees is "true")
networkFeesNotional number Network fees in valuation currency. (used if includeFees is "false")
serviceFeesQuantity number Service fees in kind. (used if includeFees is "true")
serviceFeesNotional number Service fees in valuation currency. (used if includeFees is "false")

Request a SWIFT, SEPA or WIRE withdrawal

import requests

endpoint = '%s/accounts/%s/withdrawal-requests' % (base, accountId)
body = {
   "assetId": "EUR",
   "networkId": "SEPA",
   "sourceBankId": "972b1d9c-4261-50f2-9e09-20b87ef18226",
   "bankId": "978DNQZ3FQKJ",
   "bankAccountNumber": "IK877DY1NJDQZ",
   "quantity": "100",
   "description": "My note",
   "includeFees": true,
   "virtualAccountId": null
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request a withdrawal on a "SWIFT", "SEPA" or "WIRE" bank account. The assets will be withdrawn from the Funding Account towards an external bank account.

It is possible to use your EURC balance to withdraw to a bank account that handles EUR. Same logic applies to USDC and USD.

HTTP Request

POST /accounts/:accountId/withdrawal-requests

Body Parameters

Parameter Type Description
assetId string Asset ID
bankId string Destination bank account bankId (BIC/SWIFT/ABA Routing Number) (as retrieved in the /banks route or /withdrawal-destinations route)
bankAccountNumber string Destination bank account bankAccountNumber (IBAN/Account number) (as retrieved in the /banks route or /withdrawal-destinations route)
sourceBankId string Aplo's bank account the funds will be sent from. (as retrieved in the GET /banks/internal route). Can be null in which case, the source bank is chosen automatically.
networkId string "SWIFT", "SEPA" or "WIRE"
quantity string Withdrawal request volume
description string Custom note
includeFees boolean Whether fees are included in the quantity withdrawn or not
virtualAccountId number optional Virtual account id requesting the withdrawal (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "id": "22e87620-e1a1-58bf-8c14-f4c0cc8695c4",
  "assetId": "EUR",
  "conversionAssetId": null,
  "destinationId": "12a79474-586f-5db4-8d36-4b123155746a",
  "destinationType": "externalBank",
  "quantity": "100",
  "description": "My note",
  "accountId": "45cabb50-42f7-4a69-a534-db030882f34c",
  "status": "requested",
  "includeFees": true,
  "networkFeesQuantity": "0.1",
  "serviceFeesQuantity": "0.01",
  "networkFeesNotional": "5000",
  "serviceFeesNotional": "500",
  "virtualAccountId": null
}

The response is a JSON object with the following fields:

Field Type Description
id string Withdrawal request UUID
assetId string Asset ID
conversionAssetId string The asset that was converted to assetId before being withdrawn (USDC -> USD and EURC -> EUR), will be null for withdrawals without conversion
destinationId string Destination bank UUID
destinationType string "externalBank"
quantity string Withdrawal request volume
description string Custom note
accountId string Account UUID
status string Withdrawal request status
virtualAccountId number Virtual account id (null indicates the "Main Account")
includeFees boolean Whether fees are included in the amount withdrawn
networkFeesQuantity number Network fees in kind. (used if includeFees is "true")
networkFeesNotional number Network fees in valuation currency. (used if includeFees is "false")
serviceFeesQuantity number Service fees in kind. (used if includeFees is "true")
serviceFeesNotional number Service fees in valuation currency. (used if includeFees is "false")

Get Withdrawal Requests

import requests

endpoint = '%s/accounts/%s/fund-history?type=withdrawal&status=requested&page=%s&pageSize=%d' % (base, accountId, page, pageSize)
response = requests.get(endpoint, headers=headers)

This route allows accounts to retrieve their withdrawal requests history.

HTTP Request

GET /accounts/:accountId/fund-history?type=withdrawal&status=requested

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve withdrawal requests for
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
status string Status filter: must be "complete", "processing", "canceled" or "frozen"
assetId string Asset filter

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "quantity": "1.868565",
      "sourceVirtualAccountId": "1138967864",
      "destinationVirtualAccountId": "1138967864",
      "id": "5a83f67f-aebd-4e56-99df-de5237645b41",
      "assetId": "BTC",
      "type": "withdrawal",
      "accountId": "2e530764-9228-437e-a62f-a049e6400269",
      "description": null,
      "status": "requested",
      "createdAt": "2022-07-29T08:52:15.887Z",
      "details": {
        "networkFeesQuantity": "0.0005",
        "serviceFeesQuantity": "0.000935",
        "networkFeesNotional": "11.97",
        "serviceFeesNotional": "22.39",
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "destinationId": "3cc28095-4f3b-4203-a4b2-afd1c731a790",
        "destinationType": "externalAddress",
        "paymentId": null,
        "status": "requested",
        "selectedPolicy": null,
        "validatedBy": [],
        "includeFees": true,
        "chainalysisId": null,
        "kytValidated": null,
        "virtualAccountId": 1138967864,
        "networkId": "BTC",
        "payment": null,
        "externalAddress": {
          "id": "ab34bc89-fdd8-42d2-8f11-d20f3c0e8762",
          "value": "e8309358-483d-4d03-a953-c66318679add",
          "memo": null,
          "description": "Withdrawal address Bitcoin",
          "accountId": "2e530764-9228-437e-a62f-a049e6400269",
          "isActive": true,
          "isWhitelisted": true,
          "isArchived": false,
          "virtualAccountId": null,
          "whitelistedAt": "2022-07-29T08:35:10.297Z",
          "whitelistValidators": [
            {
              "name": "User One",
              "time": 1659083710297,
              "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
              "approved": true
            }
          ],
          "isSelfBeneficiary": false,
          "isSelfHosted": false,
          "beneficiaryCountry": null,
          "beneficiaryAddress": null,
          "beneficiaryRelationship": null,
          "walletPurpose": null,
          "providerName": null,
          "providerWebsite": null,
          "providerCountry": null,
          "createdAt": "2023-11-24T13:30:55.261Z",
          "whitelistingPolicy": null,
          "userId": null,
          "name": "Withdrawal address Bitcoin",
          "isUniversal": false,
          "providerId": null,
          "beneficiaryLegalName": null,
          "beneficiaryFirstName": null,
          "beneficiaryLastName": null,
          "paymentReason": null,
          "beneficiaryActivity": null,
          "beneficiaryTaxId": null,
          "beneficiaryContactEmail": null,
          "networkId": "BTC"
        },
        "externalBank": null,
        "createdBy": {
          "id": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
          "firstname": "User",
          "lastname": "One",
          "email": "usr1@sheeldmarket.com"
        }
      }
    }
    ...
  ],
  "count": 3
}

Where data is a JSON array of object with the following fields:

Field Type Description
id string Withdrawal request UUID
quantity string Withdrawal volume
sourceVirtualAccountId number Virtual account id (null indicates the "Main Account")
destinationVirtualAccountId number Same as the sourceVirtualAccountId
assetId string Asset identifier
type string "withdrawal"
accountId string Account UUID
description string null
status string Status of the withdrawal, can be "pendingPeerApproval", "rejectedPolicy", "rejectedPeer", "requested", "processing", "approved", "frozen", "rejectedSys" or "pendingInvestigation",
createdAt date Date of withdrawal
details object Withdrawal details (see below)

details is an object with the following properties:

Field Type Description
networkFeesQuantity string Network fees (in kind)
serviceFeesQuantity string Service fees (in kind)
networkFeesNotional string Network fees (in USD)
serviceFeesNotional string Service fees (in USD)
userId string UUID of the User that made this request (most likely: you)
destinationId string Either the UUID of the destination address or the destination bank (depending on the value of destinationType) for this withdrawal
destinationType string "externalAddress" or "externalBank"
paymentId string null since this withdrawal has yet to be completed
status string Status of the withdrawal, can be "pendingPeerApproval", "rejectedPolicy", "rejectedPeer", "requested", "processing", "approved", "frozen", "rejectedSys" or "pendingInvestigation",
selectedPolicy object The selected policy regarding governed withdrawal requests or null if none were used
validatedBy array List of users who have approved/rejected this withdrawal request (only used for governed withdrawal requests)
includeFees boolean Whether or not fees were included in the withdrawn amount (false means notional fees will be charged on the account's "billing" sub account, true means the fees are directly deducted from the quantity withdrawn)
chainalysisId string Potential Chainalysis Id (can be null)
kytValidated boolean Whether Aplo's KYT has been validated for this request
virtualAccountId number Virtual account Id (null indicates the "Main Account")
networkId string Network id (see /networks)
payment object null since this request has yet to be completed
externalAddress object The details about the address used to make the withdrawal (see this route for the complete properties) (null for fiat withdrawals)
externalBank object The details about the bank used to make the withdrawal (see this route for the complete properties) (null for non-fiat withdrawals)
createdBy object Details about the user that requested this request

Get Deposits History

import requests

endpoint = '%s/accounts/%s/fund-history?type=deposit&page=%s&pageSize=%d' % (base, accountId, page, pageSize)
response = requests.get(endpoint, headers=headers)

This route allows accounts to retrieve theirs deposit history.

HTTP Request

GET /accounts/:accountId/fund-history?type=deposit

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve withdrawal requests for
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
status string Status filter: must be "complete", "processing", "canceled" or "frozen"
assetId string Asset filter

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "quantity": "50",
      "sourceVirtualAccountId": "1138967864",
      "destinationVirtualAccountId": "1138967864",
      "id": "3ee6e336-b557-446d-afb2-a3fc6240e625",
      "assetId": "ETH",
      "type": "deposit",
      "accountId": "2e530764-9228-437e-a62f-a049e6400269",
      "description": "ETH deposit",
      "status": "complete",
      "createdAt": "2022-07-25T14:54:28.512Z",
      "details": {
        "networkFees": "0",
        "serviceFees": "0",
        "txId": "b5993828-eb81-49dd-adcc-f51feeb539a2",
        "type": "deposit",
        "status": "complete",
        "chainalysisId": null,
        "kytValidated": null,
        "virtualAccountId": 1138967864,
        "networkId": "ETH",
        "notional": "25000",
        "sourceType": "externalAddress",
        "sourceId": null,
        "destinationType": "internalAddress",
        "destinationId": "d6182c41-fdc6-4f0b-a2df-c98adcf5d849",
        "feesAssetId": "ETH",
        "sourceExternalAddress": null,
        "destinationInternalAddress": {
          "id": "d6182c41-fdc6-4f0b-a2df-c98adcf5d849",
          "value": "cad245f5-8ed1-4d27-bcd3-c416e87c923f",
          "memo": null,
          "description": "Virtual Withdrawal address Ethereum usr1+virtual1@sheeldmarket.com",
          "accountId": "2e530764-9228-437e-a62f-a049e6400269",
          "virtualAccountId": 1138967864,
          "createdAt": "2022-07-25T14:54:28.512Z",
          "networkId": "ETH"
        },
        "sourceExternalBank": null,
        "destinationInternalBank": null
      }
    }
    ...
  ],
  "count": 3
}

Where data is a JSON array of object with the following fields:

Field Type Description
quantity string Withdrawal volume
sourceVirtualAccountId number Virtual account id (null indicates the "Main Account")
destinationVirtualAccountId number Same as the sourceVirtualAccountId
id string UUID of the deposit payment
assetId string Asset identifier
type string "deposit"
accountId string Account UUID
description string Human readable description
status string "sent","error","processing","pendingInvestigation","pendingReview","complete" or "frozen"
createdAt date Date of deposit
details object Deposit details (see below)

details is an object with the following properties:

Field Type Description
networkFees string Amount of network fees
serviceFees string Amount of service fees
feesAssetId string Asset of the fees (either in kind or USD)
id string UUID of the payment linked to the deposit
txId string Transaction Hash
description string Human readable description
type string "deposit"
status string "sent","error","processing","pendingInvestigation","pendingReview","complete" or "frozen"
chainalysisId string The optional Chainalysis Id
kytValidated boolean Whether the KYT has been validated on Aplo's end
virtualAccountId number Virtual account Id (null indicates the "Main Account")
networkId string Network id (see /networks)
notional string Notional value of the deposit payment
sourceType string "externalAddress" for crypto deposits, or "externalBank" for fiat deposits
sourceId string Source Id (can be null)
destinationType string "internalAddress" for crypto deposits, or "internalBank" for fiat deposits
destinationId string Destination Id
sourceExternalAddress object If sourceType = "externalAddress", the destination external address, otherwise null (see this route for the complete properties)
destinationInternalAddress object If destinationType = "internalAddress", the destination internal address, otherwise null (see this route for the complete properties)
sourceExternalBank object If sourceType = "externalBank", the source external bank, otherwise null (see this route for the complete properties)
destinationInternalBank object If destinationType = "internalBank", the destination internal bank, otherwise null (see this route for the complete properties)

Fiat deposits have an sourceExternalBank and a destinationInternalBank.

Get Withdrawals History

import requests

endpoint = '%s/accounts/%s/fund-history?type=withdrawal&status=complete&page=%s&pageSize=%d' % (base, accountId, page, pageSize)
response = requests.get(endpoint, headers=headers)

This route allows accounts to retrieve their withdrawal history (not to be confused with the history for withdrawal requests).

HTTP Request

GET /accounts/:accountId/fund-history?type=withdrawal&status=complete

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve withdrawal requests for
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
status string Status filter: must be "complete", "processing", "canceled" or "frozen"
assetId string Asset filter

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "quantity": "1.868565",
      "sourceVirtualAccountId": "1138967864",
      "destinationVirtualAccountId": "1138967864",
      "id": "65cc1c14-5e1b-4b54-82fa-f47460479718",
      "assetId": "BTC",
      "type": "withdrawal",
      "accountId": "2e530764-9228-437e-a62f-a049e6400269",
      "description": null,
      "status": "approved",
      "createdAt": "2022-08-01T09:14:59.536Z",
      "details": {
        "networkFeesQuantity": "0.0005",
        "serviceFeesQuantity": "0.000935",
        "networkFeesNotional": "11.66",
        "serviceFeesNotional": "21.81",
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "destinationId": "3cc28095-4f3b-4203-a4b2-afd1c731a790",
        "destinationType": "externalAddress",
        "paymentId": "56e2b7bf-2740-4397-9c69-21f190338629",
        "status": "approved",
        "selectedPolicy": null,
        "validatedBy": [],
        "includeFees": true,
        "chainalysisId": null,
        "kytValidated": null,
        "virtualAccountId": 1138967864,
        "networkId": "BTC",
        "payment": {
          "quantity": "1.868565",
          "networkFees": "0.0005",
          "serviceFees": "0.000935",
          "id": "56e2b7bf-2740-4397-9c69-21f190338629",
          "txId": "9787YJLPDGUIQD09",
          "description": "Monthly withdrawal",
          "destinationType": "externalAddress",
          "type": "withdrawal",
          "status": "complete",
          "chainalysisId": null,
          "kytValidated": null,
          "virtualAccountId": 1138967864,
          "networkId": "BTC",
          "notional": "32082.42",
          "createdAt": "2022-08-01T09:15:21.374Z",
          "sourceId": "5a58dfbb-f686-4665-a7b8-f0e344bedd1c",
          "destinationId": "3cc28095-4f3b-4203-a4b2-afd1c731a790",
          "assetId": "BTC",
          "feesAssetId": "BTC",
          "accountId": "2e530764-9228-437e-a62f-a049e6400269",
          "destinationExternalAddress": {
            "id": "ab34bc89-fdd8-42d2-8f11-d20f3c0e8762",
            "value": "e8309358-483d-4d03-a953-c66318679add",
            "memo": null,
            "description": "Withdrawal address Bitcoin",
            "accountId": "2e530764-9228-437e-a62f-a049e6400269",
            "isActive": true,
            "isWhitelisted": true,
            "isArchived": false,
            "virtualAccountId": null,
            "whitelistedAt": "2022-07-29T08:35:10.297Z",
            "whitelistValidators": [
              {
                "name": "User One",
                "time": 1659083710297,
                "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
                "approved": true
              }
            ],
            "isSelfBeneficiary": false,
            "isSelfHosted": false,
            "beneficiaryCountry": null,
            "beneficiaryAddress": null,
            "beneficiaryRelationship": null,
            "walletPurpose": null,
            "providerName": null,
            "providerWebsite": null,
            "providerCountry": null,
            "createdAt": "2023-11-24T13:30:55.261Z",
            "whitelistingPolicy": null,
            "userId": null,
            "name": "Withdrawal address Bitcoin",
            "isUniversal": false,
            "providerId": null,
            "beneficiaryLegalName": null,
            "beneficiaryFirstName": null,
            "beneficiaryLastName": null,
            "paymentReason": null,
            "beneficiaryActivity": null,
            "beneficiaryTaxId": null,
            "beneficiaryContactEmail": null,
            "networkId": "BTC"
          },
          "sourceInternalAddress": null,
          "destinationExternalBank": null,
          "sourceInternalBank": null
        },
        "externalAddress": {
          "id": "ab34bc89-fdd8-42d2-8f11-d20f3c0e8762",
          "value": "e8309358-483d-4d03-a953-c66318679add",
          "memo": null,
          "description": "Withdrawal address Bitcoin",
          "accountId": "2e530764-9228-437e-a62f-a049e6400269",
          "isActive": true,
          "isWhitelisted": true,
          "isArchived": false,
          "virtualAccountId": null,
          "whitelistedAt": "2022-07-29T08:35:10.297Z",
          "whitelistValidators": [
            {
              "name": "User One",
              "time": 1659083710297,
              "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
              "approved": true
            }
          ],
          "isSelfBeneficiary": false,
          "isSelfHosted": false,
          "beneficiaryCountry": null,
          "beneficiaryAddress": null,
          "beneficiaryRelationship": null,
          "walletPurpose": null,
          "providerName": null,
          "providerWebsite": null,
          "providerCountry": null,
          "createdAt": "2023-11-24T13:30:55.261Z",
          "whitelistingPolicy": null,
          "userId": null,
          "name": "Withdrawal address Bitcoin",
          "isUniversal": false,
          "providerId": null,
          "beneficiaryLegalName": null,
          "beneficiaryFirstName": null,
          "beneficiaryLastName": null,
          "paymentReason": null,
          "beneficiaryActivity": null,
          "beneficiaryTaxId": null,
          "beneficiaryContactEmail": null,
          "networkId": "BTC"
        },
        "externalBank": null,
        "createdBy": {
          "id": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
          "firstname": "User",
          "lastname": "One",
          "email": "usr1@sheeldmarket.com"
        }
      }
    }
    ...
  ],
  "count": 3
}

The returned body is the same as the withdrawal request history route except details.payment has the following additional properties instead of being null:

Field Type Description
quantity string The quantity withdrawn
assetId string Asset being withdrawn
networkFees string Amount of network fees
serviceFees string Amount of service fees
feesAssetId string Asset of the fees (either in kind or USD)
id string UUID of the payment linked to the withdrawal
txId string Transaction Hash
description string Human readable description
sourceType string null for crypto withdrawals, or "internalBank" for fiat withdrawals
destinationType string Either "externalAddress" or "externalBank" depending on the asset being withdrawn
type string "withdrawal"
status string "sent","error","processing","pendingInvestigation","pendingReview","complete" or "frozen"
chainalysisId string The optional Chainalysis Id
kytValidated boolean Whether the KYT has been validated on Aplo's end
virtualAccountId number Virtual account Id (null indicates the "Main Account")
networkId string Network id (see /networks)
notional string Notional value of the deposit payment
createdAt date Date of payment creation (ie. validation of withdrawal)
sourceId string Source Id
destinationId string Destination Id
accountId string Account UUID
destinationExternalAddress object If destinationType = "externalAddress", the destination external address, otherwise null (see this route for the complete properties)
sourceInternalAddress object If sourceType = "internalAddress", the source internal address, otherwise null (see this route for the complete properties)
destinationExternalBank object If destinationType = "externalBank", the destination external bank, otherwise null (see this route for the complete properties)
sourceInternalBank object If sourceType = "internalBank", the source internal bank, otherwise null (see this route for the complete properties)

Fiat withdrawals have an sourceInternalBank and a destinationExternalBank.

Request a Transfer

import requests

endpoint = '%s/accounts/%s/transfer-requests' % (base, accountId)
body = {
   "assetId": "BTC",
   "sourceId": "DEM1",
   "destinationId": "funding",
   "sourceVirtualAccountId": null,
   "destinationVirtualAccountId": 8742238924,
   "quantity": "100",
   "description": "My note",
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request a transfer.
You can transfer funds between different virtual accounts.
The assets will be withdrawn from source towards the destination.

HTTP Request

POST /accounts/:accountId/transfer-requests

Body Parameters

Parameter Type Description
assetId string Asset ID
sourceId string Source Id: can be an MPID or "funding"
destinationId string Destination Id: can be an MPID or "funding"
quantity string Transfer request volume
description string Custom note
sourceVirtualAccountId number optional Source Virtual account id (null indicates the "Main Account")
destinationVirtualAccountId number optional Destination Virtual account id (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "id": "107849b8-40d2-5d56-82e1-9dee587b16a6",
  "sourceId": "DEM1",
  "destinationId": "funding",
  "description": "My note",
  "userId": "cf933712-4608-5989-bcc2-d71b15c7bad4",
  "accountId": "d940fbba-13a1-5d30-9a1b-f59f4918122c",
  "sourceVirtualAccountId": null,
  "destinationVirtualAccountId": 8742238924,
  "assetId": "BTC",
  "status": "processing",
  "quantity": "100",
  "createdAt": "2020-08-07T15:42:47.138Z"
}

The response is a JSON object with the following fields:

Field Type Description
id string Transfer request UUID
sourceId string Id of the source of the transfer (can be an MPID or "funding")
destinationId string Id of the destination of the transfer (can be an MPID or "funding")
userId string UUID of the User that made this request (most likely, you)
accountId string Account UUID
sourceVirtualAccountId number Source Virtual account id (null indicates the "Main Account")
destinationVirtualAccountId number Source Virtual account id (null indicates the "Main Account")
assetId string Asset identifier
status string Status of the transfer, can be "requested", "processing", "approved" or "rejected"
quantity string Transfer volume
createdAt date Date of transfer

Get Transfers History

import requests

endpoint = '%s/accounts/%s/fund-history?type=transfer&page=%s&pageSize=%d' % (base, accountId, page, pageSize)
response = requests.get(endpoint, headers=headers)

This route allows accounts to retrieve theirs transfer requests history.

HTTP Request

GET /accounts/:accountId/fund-history?type=transfer

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve withdrawal requests for
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
status string Status filter: must be "complete", "processing", "canceled" or "frozen"
assetId string Asset filter

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "id": "41e6a0cb-33e9-46ac-8c36-9cb6cb91ce9d",
      "quantity": "8.234",
      "sourceVirtualAccountId": null,
      "destinationVirtualAccountId": 97842452,
      "assetId": "ETH",
      "type": "transfer",
      "accountId": "2e530764-9228-437e-a62f-a049e6400269",
      "description": null,
      "status": "requested",
      "createdAt": "2022-08-01T09:03:25.125Z",
      "details": {
        "destinationId": "SONE",
        "destinationVirtualAccountId": 97842452,
        "sourceId": "funding",
        "sourceVirtualAccountId": null,
        "userId": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
        "status": "requested",
        "createdBy": {
          "id": "ab35e86e-8ce1-446e-b0d7-d33b1bd6b0bc",
          "firstname": "User",
          "lastname": "One",
          "email": "usr1@sheeldmarket.com"
        },
        "sourceVirtualAccount": null,
        "destinationVirtualAccount": {
          "id": 97842452,
          "email": "larry.het@aplo.io",
          "name": "Larry Het"
        }
      }
    }
  ],
  "count": 3
}

Where data is a JSON array of object with the following fields:

Field Type Description
id string Transfer request UUID
quantity string Transfer volume
sourceVirtualAccountId number Source Virtual account id (null indicates the "Main Account")
destinationVirtualAccountId number Destination Virtual account id (null indicates the "Main Account")
assetId string Asset identifier
type string "transfer"
accountId string Account UUID
description string null
status string Status of the transfer, can be "requested", "processing", "approved" or "rejected"
createdAt string Date of transfer
details object Transfer details (see below)

details is an object with the following properties:

Field Type Description
sourceId string Id of the source of the transfer (can be an MPID or "funding")
sourceVirtualAccountId number Virtual account id for the source of the transfer (null indicates the "Main Account")
destinationId string Id of the destination of the transfer (can be an MPID or "funding")
destinationVirtualAccountId number Virtual account id for the destination of the transfer (null indicates the "Main Account")
userId string UUID of the User that made this request (most likely: you)
createdBy object Details about the user that requested this request
sourceVirtualAccount object Details about the source virtual account (null indicates the "Main account")
destinationVirtualAccount object Details about the destination virtual account (null indicates the "Main account")

Get billing balance

import requests

endpoint = '%s/accounts/%s/billing/balance' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allows accounts to retrieve the current billing balance of a virtual account ("Main Account" by default).

HTTP Request

GET /accounts/:accountId/billing/balance

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve the billing balance for (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "USD": {
    "outstandingInvoices": "21500",
    "refundBalance": "549.83"
  },
  "EUR": {
    "outstandingInvoices": "1000",
    "refundBalance": "0"
  }
}

This route returns both the total outstanding invoice amount and refund balance for both USD and EUR.
To get the details of the due invoices, you can use the GET invoices route and filter on the status.

Get invoices

import requests

endpoint = '%s/accounts/%s/billing/invoices' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route allows accounts to retrieve all their invoices.

HTTP Request

GET /accounts/:accountId/billing/invoices

This route can take the following optional query parameters:

Parameter Type Description
virtualAccountId number Specific virtual account to retrieve the billing balance for (null indicates the "Main Account")
status string Filter on invoice status, can be "paid" or "due"
invoiceNumber string Text filter on invoice number (can be partial match)
issueDateStart number or string Filter on issue date. Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
issueDateEnd number or string Filter on issue date. Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
dueDateStart number or string Filter on due date. Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
dueDateEnd number or string Filter on due date. Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
isCanceled boolean Whether or not to filter out canceled invoices

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "id": "93a713a3-aa98-508a-b10d-0f179fce8fe6",
      "invoiceNumber": "F-2024-23082",
      "invoiceNumberSequence": "23082",
      "isSubjectToVat": false,
      "issueDate": "2024-01-01",
      "dueDate": "2024-02-01",
      "fileName": "aplo-invoice-F-2024-23082.pdf",
      "status": "paid",
      "totalAmount": "12400",
      "currencyId": "USD",
      "accountId": "4132f517-d453-5615-80f1-6ee043db4ad5",
      "virtualAccountId": null,
      "creditNoteId": null,
      "settlements": [
        {
          "id": "4",
          "createdAt": "2024-01-10 10:12:33+00",
          "createdBy": "Test User (test.user@email.com)",
          "accountId": "4132f517-d453-5615-80f1-6ee043db4ad5",
          "virtualAccountId": null,
          "sourceSubAccount": "funding",
          "rate": "1",
          "quantity": "12400",
          "totalQuantity": "12400",
          "currencyId": "USD",
          "refundQuantity": "0",
          "refundCurrencyId": "USD",
          "totalRefundQuantity": "0",
          "totalSettled": "12400",
          "targetCurrencyId": "USD",
          "description": "Settlement for invoice F-2024-23082"
        }
      ],
      "billingItems": [
        {
          "id": "8",
          "accountId": "4132f517-d453-5615-80f1-6ee043db4ad5",
          "virtualAccountId": null,
          "status": "paid",
          "name": "Charge example",
          "description": "Here is a nice description",
          "category": "Fee",
          "subCategory": null,
          "currencyId": "USD",
          "vatRate": "0",
          "isSubjectToVat": false,
          "type": "charge",
          "eventTime": "2024-01-01 08:00:00+00",
          "unitPrice": "10000",
          "quantity": "1",
          "value": "10000",
          "vatValue": "0",
          "totalValue": "10000",
          "invoiceNumber": "23082",
          "creditNoteId": null,
          "billingSettlementId": null,
          "settlement": null
        },
        {
          "id": "12",
          "accountId": "4132f517-d453-5615-80f1-6ee043db4ad5",
          "virtualAccountId": null,
          "status": "paid",
          "name": "Another one",
          "description": null,
          "category": "Fee",
          "subCategory": "Trading fee",
          "currencyId": "USD",
          "vatRate": "0",
          "isSubjectToVat": false,
          "type": "charge",
          "eventTime": "2024-01-01 08:10:00+00",
          "unitPrice": "400",
          "quantity": "1",
          "value": "400",
          "vatValue": "0",
          "totalValue": "400",
          "invoiceNumber": "23082",
          "creditNoteId": null,
          "billingSettlementId": null,
          "settlement": null
        }
      ]
    },
    {
      "id": "bb868349-fc86-5902-bf38-f7a38d6d8a84",
      "invoiceNumber": "F-2024-23098",
      "invoiceNumberSequence": "23098",
      "isSubjectToVat": true,
      "issueDate": "2024-02-01",
      "dueDate": "2024-03-01",
      "fileName": "aplo-invoice-F-2024-23098.pdf",
      "status": "due",
      "totalAmount": "6000",
      "currencyId": "EUR",
      "accountId": "4132f517-d453-5615-80f1-6ee043db4ad5",
      "virtualAccountId": null,
      "creditNoteId": null,
      "settlements": [],
      "billingItems": [
        {
          "id": "28",
          "accountId": "4132f517-d453-5615-80f1-6ee043db4ad5",
          "virtualAccountId": null,
          "status": "due",
          "name": "Banking Fee",
          "description": null,
          "category": null,
          "subCategory": null,
          "currencyId": "EUR",
          "vatRate": "0.2",
          "isSubjectToVat": true,
          "type": "charge",
          "eventTime": "2024-02-04 12:13:00+00",
          "unitPrice": "5000",
          "quantity": "1",
          "value": "5000",
          "vatValue": "1000",
          "totalValue": "6000",
          "invoiceNumber": "23098",
          "creditNoteId": null,
          "billingSettlementId": null,
          "settlement": null
        },
      ]
    }, ...
  ],
  "count": 12
}

Where data is a JSON array of objects with the following properties:

Header Type Description
id string UUID of the invoice
invoiceNumber string Human readable number of the invoice
invoiceNumberSequence string Sequence number of the invoice number
isSubjectToVat boolean Whether this invoice is subject to VAT or not
issueDate string Date of issuance
dueDate string Due date for the invoice
fileName string Name of the PDF file for this invoice
status string "due" or "paid"
totalAmount string The total amount of currency this invoice is for
currencyId string "USD" or "EUR"
accountId string Account identifier
virtualAccountId number Virtual account id (null indicates the "Main Account")
creditNoteId string Credit note in case the invoice has been canceled. null otherwise
settlements Array Array of settlements, for now partial settlement of invoices is not supported, so only the first element will be present or not
billingItems Array The details of the invoice items

billingItems is a sub-array of JSON objects with the following properties

Header Type Description
id string Unique billing item id
accountId string Account identifier
virtualAccountId number Virtual account id (null indicates the "Main Account")
status string "due" or "paid"
name string Name of the billing item
description string Potential description for this item (can be null)
category string Potential category for this item (can be null)
subCategory string Potential sub category for this item (can be null)
currencyId string "USD" or "EUR"
vatRate string The VAT rate for this item ("0") if not subject to VAT
isSubjectToVat boolean Whether this item is subject to VAT or not
type string "charge" or "rebate" (rebates will have negative values for unitPrice and other number columns)
eventTime string Time of item billing
unitPrice string The unit price for this item
quantity string Number of item
value string unitPrice * quantity
vatValue string unitPrice * quantity * vatRate
totalValue string value + vatValue (should be identical to value for item not subject to VAT)
invoiceNumber string Number of the invoice this item belongs to
creditNoteId string Credit note in case the invoice has been canceled. null otherwise
billingSettlementId string Only used for pre-settled billing items, null otherwise
settlement Object Only used for pre-settled billing items, null otherwise

settlements and billingItems.settlement are JSON objects with the following properties

Header Type Description
id string Unique settlement id
accountId string Account identifier
virtualAccountId number Virtual account id (null indicates the "Main Account")
createdAt string Date of settlement
createdBy string Which user settled this invoice/item
sourceSubAccount string Source of funds for the settlement "funding" for invoice settlements, "outgoingFunding" for automatic withdrawal fees settlement
rate string Rate of conversion if needed.
quantity string Quantity settled (in currencyId)
totalQuantity string quantity * rate (in targetCurrencyId)
currencyId string The currency used for this settlement
refundQuantity boolean The billingRefund quantity being used to settle (in refundCurrencyId)
refundCurrencyId string "USD" or "EUR", the currency of the billingRefund being used
totalRefundQuantity string refundQuantity * rate (in targetCurrencyId)
totalSettled string totalQuantity + totalRefundQuantity (in targetCurrencyId)
targetCurrencyId string "USD" or "EUR", the currency of the invoice/billingItem being settled
description string Human readable description

Settle invoice

import requests

endpoint = '%s/accounts/%s/billing/invoices/%s/settle' % (base, accountId, invoiceId)
body = {
   "assetId": "USDT",
}
response = requests.post(endpoint, headers=headers, json=body)

Allow users to settle a "due" invoice. Note: you shouldn't use invoiceNumber here but the id property of an invoice (which is a UUID).

You can settle a "USD" invoice using "USDT", "USDC" or "USD" without the use of a conversion.
You can only settle a "EUR" invoice using "EUR" without the use of a conversion.

You can settle a "USD" invoice using "EUR" or a "EUR" invoice using "USDT", "USDC" or "USD" by providing an optional token property in the body. To get this token, please use the GET invoice token route.

HTTP Request

POST /accounts/:accountId/billing/invoices/:invoiceId/settle

Body Parameters

Parameter Type Description
assetId string "USDT", "USDC", "USD" or "EUR"
token string optional The conversion JWT (see above)

Response fields

This route returns the settlement object, see the GET invoices route for the settlement properties

Get invoice token

import requests

endpoint = '%s/accounts/%s/billing/invoice/%s/token' % (base, accountId, invoiceId)
response = requests.get(endpoint, headers=headers)

This route allows accounts to generate a JWT guaranteeing a fixed rate of conversion between "USD" and "EUR" for a period of 10 minutes.
Note: you shouldn't use invoiceNumber here but the id property of an invoice (which is a UUID).
You can then use this token to settle an invoice using a different currency than the invoice (see the settle invoice route for more information)

HTTP Request

GET /accounts/:accountId/billing/invoices/:invoiceId/token

Response fields

Example of JSON structure returned by the request:

{
  "token": "DOI3JR3IDJQ034.FQZJDO12OR89F8DF.234523"
}

Request staking an asset

import requests

endpoint = '%s/accounts/%s/stake' % (base, accountId)
body = {
   "assetId": "SOL",
   "quantity": "1000",
   "virtualAccountId": null
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request staking an asset.
The asset will be transferred from the Funding Account towards the Staking Sub Account.

HTTP Request

POST /accounts/:accountId/stake

Body Parameters

Parameter Type Description
assetId string Asset ID
quantity string Staking volume
virtualAccountId number optional Virtual account id requesting the stake request (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "id": "87ccf43f-225e-4c77-9e32-7fdc4693e870",
  "assetId": "SOL",
  "accountId": "45cabb50-42f7-4a69-a534-db030882f34c",
  "virtualAccountId": null,
  "status": "pending",
  "type": "stake",
  "quantity": "1000",
  "day": "2025-11-13",
  "notional": "153000",
  "createdAt": "2025-11-13T14:47:10.334Z",
  "requestedBy": "User One (usr1@aplo.io)"
}

The response is a JSON object with the following fields:

Field Type Description
id string Stake request UUID
assetId string Asset ID
accountId string Account UUID
virtualAccountId number Virtual account id (null indicates the "Main Account")
status string Stake request status
type string Stake request type (stake or unstake)
quantity string Stake request volume
day string The session of the request
notional string The notional value of the request
createdAt string ISO date of the request
requestedBy string The initiator of the request

Request unstaking an asset

import requests

endpoint = '%s/accounts/%s/unstake' % (base, accountId)
body = {
   "assetId": "SOL",
   "quantity": "1000",
   "virtualAccountId": null
}
response = requests.post(endpoint, headers=headers, json=body)

This route allows market participants to request unstaking an asset.
The asset will be transferred from the Staking Sub Account towards the Funding Account.

HTTP Request

POST /accounts/:accountId/unstake

Body Parameters

Parameter Type Description
assetId string Asset ID
quantity string Unstaking volume
virtualAccountId number optional Virtual account id requesting the unstake request (null indicates the "Main Account")

Response fields

Example of JSON structure returned by the request:

{
  "id": "87ccf43f-225e-4c77-9e32-7fdc4693e870",
  "assetId": "SOL",
  "accountId": "45cabb50-42f7-4a69-a534-db030882f34c",
  "virtualAccountId": null,
  "status": "pending",
  "type": "unstake",
  "quantity": "1000",
  "day": "2025-11-13",
  "notional": "153000",
  "createdAt": "2025-11-13T14:47:10.334Z",
  "requestedBy": "User One (usr1@aplo.io)"
}

The response is a JSON object with the following fields:

Field Type Description
id string Request UUID
assetId string Asset ID
accountId string Account UUID
virtualAccountId number Virtual account id (null indicates the "Main Account")
status string Request status
type string Request type (stake or unstake)
quantity string Unstaking volume
day string The session of the request
notional string The notional value of the request
createdAt string ISO date of the request
requestedBy string The initiator of the request

Fund Administration

Get activity

import requests

endpoint = '%s/user/activity?start=%s&asset=%s&subAccount=%s' % (base, start, asset, subAccount)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve their account and subAccount activity.
This route takes the following optional query parameters:

Parameter Type Description
asset string Asset filter
accountId string Account UUID that the user has access to (can be retrieved with the /user route)
subAccount string "billing" (for billing account activity) or a 4-character Market participant ID that the user has access to (can be retrieved with the /user route)
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
order string The sort order (by time), can be "asc" or "desc" (defaults to "asc")
virtualAccountId number Specific virtual account to retrieve activity for

One of start and end MUST be provided (both can be provided at once).

HTTP Request

GET /user/activity

If pagination is not used, results will be streamed as chunks of JSON objects (using the transfer-encoding header)
This is the prefered way of getting large amount of records at once, but be aware that this may present long wait before the query fully finishes.

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "time": "2021-03-10T09:27:36.088Z",
      "type": "deposit",
      "asset": "BTC",
      "quantity": "20",
      "updatedBalance": "20",
      "subAccount": "SHLD",
      "activityId": "Ooi9873jBDX423237Osg450lnc0985hyD3fSSA",
      "activityNote": "4bd70033-6266-4677-b5f2-5df9d7e05c2b",
      "activityTime": "2021-03-09T10:00:00.000Z",
      "virtualAccountId": null,
      "assetName": "BTC"
    }
  ],
  "count": 329
}

Where data is a JSON array of objects with the following properties:

Header Type Description
time Date ISO date of when the activity was entered in our system's books
type string Type of activity, can be "deposit", "withdrawal", "transfer", "trade", "rebate", "charge", "conversion" or "settlement"
asset string Aplo Asset identifier
quantity string Volume added or removed from the balance (can be negative)
updatedBalance string Balance of the account or subAccount for this asset after this activity
subAccount string Sub account impacted by this line.
activityId string Relevant ID based on the activity type (see below)
activityNote string Additional information based on the activity type (see below)
activityTime string ISO date of the event that lead to this line (Examples: for airdrops, activityTime is the actual reception time, and time is the time we notified the airdrop.)
virtualAccountId number Virtual account id (null indicates the "Main Account")
assetName string Human readable asset name (for SPOT assets, it is identical to the asset property)

activityId value based on type:

Type ID description
deposit Transaction ID
withdrawal Transaction ID
transfer none
trade Match ID (mid)
rebate Billing ID
charge Billing ID
conversion none
settlement Settlement ID

activityNote value based on type:

Type Note
deposit Source address
withdrawal Destination address
transfer none
trade Order token
rebate Custom note
charge Custom note
conversion none
settlement Settlement name

Get activity report

import requests

endpoint = '%s/user/activity/report?start=%s&asset=%s&subAccount=%s' % (base, start, asset, subAccount)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve their account and subAccount activity as a CSV file.
This route takes the same optional query parameters as the JSON route except it doesn't support pagination.

HTTP Request

GET /user/activity/report

Response fields

Example of CSV file returned by the request:

Time, Type, Asset, Quantity, Updated balance, Sub Account, Activity ID, Activity Note, Activity Time, Virtual Account Id, Asset Name
2021-03-10T09:27:36.088Z, deposit, BTC, 20, 20, SHLD, Ooi9873jBDX423237Osg450lnc0985hyD3fSSA, 2021-03-09T10:00:00.000Z, 4bd70033-6266-4677-b5f2-5df9d7e05c2b,,BTC

For information about the CSV columns see the JSON route

Get balances

import requests

endpoint = '%s/user/balances?date=%s&asset=%s' % (base, start, asset)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve their account and subAccount balances. This route takes the following optional query parameters:

Parameter Type Description
format string Whether asset keys are ids or names. Can be "id" or "name", Default: "name"
accountId string Account UUID that the user has access to (can be retrieved with the /user route)
asset string Asset identifier
date number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
virtualAccountId number Specific virtual account to retrieve balances for

HTTP Request

GET /user/balances

Response fields

Example of JSON structure returned by the request:

{
  "date": "2022-03-04T09:36:35.592Z",
  "total": {
    "BTC": "5",
    "ETH": "50",
    "USDT": "10000"
  },
  "subAccounts": {
    "funding": {
      "BTC": "2",
      "ETH": "10"
    },
    "SONE": {
      "USDT": "5000"
    },
    "earning": {
      "USDT": "4000"
    },
    "incomingEarn": {
      "SONE": {
        "USDT": "1000"
      }
    },
    "outgoingEarn": {
      "BTC": "2",
      "ETH": "40"
    }
  },
  "virtualAccountId": null
}

date is the date of the balances. Defaults to the current time or the date query param, if provided.
The subAccounts property is a JSON object with sub accounts for keys with respective balances as values.
The virtualAccountId property is the virtual account requested (null by default).

Depending on the format parameter, asset keys will either be our internal asset id or asset names. This is only relevant for non-SPOT assets

For example:

Id Name
BTC BTC
wBTC_A BTC-USDT.PERP-USDT-Binance

Orders History

import requests

endpoint = '%s/user/orders?start=%s&end=%s' % (base, start, end)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve their order activity This route takes the following optional query parameters:

Parameter Type Description
asset string Asset filter
accountId string Account UUID that the user has access to (can be retrieved with the /user route)
mpid string 4-character Market participant ID that the user has access to (can be retrieved with the /user route). If supplied, overwrites the account parameter.
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
hideClosed boolean Filters out unfilled closed orders, accepts "true" (default) or "false"
order string The sort order (by time), can be "asc" or "desc" (defaults to "asc") (Only used with pagination)
virtualAccountId number Specific virtual account to retrieve orders for

One of start and end MUST be provided (both can be provided at once).

HTTP Request

GET /user/orders

If pagination is not used, results will be streamed as chunks of JSON objects (using the transfer-encoding header)
This is the prefered way of getting large amount of records at once, but be aware that this may present long wait before the query fully finishes.

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "time": "2021-01-06T13:41:55.348Z",
      "closingTime": "2021-01-06T14:12:55.348Z",
      "initialDay": "2021-01-06",
      "day": "2021-01-06",
      "user": "undefined",
      "mpid": "SHLD",
      "orderId": "3061388281894476",
      "status": "closed",
      "type": "IDO",
      "side": "Buy",
      "asset": "BTC",
      "currency": "USDT",
      "requestedVolume": "1.0001",
      "requestedPrice": "18000.43",
      "executedVolume": "0.9998",
      "averagePrice": "15000.43",
      "total": "14997.429914",
      "executionCount": "5",
      "virtualAccountId": null,
      "assetName": "BTC"
    },
    {
      "time": "2021-01-06T13:41:55.348Z",
      "closingTime": "2021-01-06T14:12:55.348Z",
      "initialDay": "2021-01-06",
      "day": "2021-01-06",
      "user": "undefined",
      "mpid": "SHLD",
      "orderId": "8715",
      "status": "closed",
      "type": "IDO",
      "side": "Buy",
      "asset": "wBTC_C",
      "currency": "USDT",
      "requestedVolume": "1.0001",
      "requestedPrice": "18000.43",
      "executedVolume": "0.9998",
      "averagePrice": "15000.43",
      "total": "14997.429914",
      "executionCount": "5",
      "virtualAccountId": null,
      "assetName": "BTC-USDT.PERP-Binance"
    }
  ],
  "count": 129
}

Where data is a JSON array of objects with the following properties:

Header Type Description
time Date ISO date of Order creation
closingTime Date ISO date of Order closing or null if the order is still open
initialDay Date Session of Order creation
day Date Last session of Order lifetime
user string Name of the user that created this order (or "undefined" if not provided)
mpid string 4-character Market participant ID
orderId string Unique token supplied at order creation
status string "received", "open" or "closed"
type string Can be "DAY", "GTC", "IOC", "IDO", "IGO", "ISO", "VIO", "TWAP", "VWAP", "VTO", "SLO", "TPO", "VTO", "PTO", "LMT", "MKT" or "DCA"
side string "S" or "B"
asset string Asset identifier
currency string Currency identifier
requestedVolume string Requested volume at Order creation (can be "null" for notional orders)
requestedPrice string Requested price at Order creation (can be "null" for "MKT" or "DCA" orders)
executedVolume string Volume executed so far
averagePrice string Average price of executions
total string Total volume of currency traded for this Order
executionCount number Number of executions for this Order
virtualAccountId number Virtual account id (null indicates the "Main Account")
assetName string Human readable asset name (for SPOT assets, it is identical to the asset property)

Orders history report

import requests

endpoint = '%s/user/orders/report?start=%s&end=%s' % (base, start, end)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve a CSV report of their order activity The returned data is not ordered in any way for performance reasons. (Except if pagination is used)
This route takes the same optional query parameters as the JSON route except it doesn't support pagination.

HTTP Request

GET /user/orders/report

Response fields

Example CSV file returned by the request:

  Time,ClosingTime,Day,InitialDay User,MPID,OrderId,Status,Type,Side,Asset,Currency,Requested Volume,Requested Price,Executed Volume,Average Price,Total,Execution Count,Virtual Account Id,Asset Name
  2021-01-06T13:41:55.348Z,2021-01-06T13:41:55.348Z,2021-01-06,2021-01-06,SHLD,undefined,3061388281894476,closed,IDO,Buy,BTC,USDT,1.0001,18000.43,0.9998,15000.43,14997.429914,5,,BTC

For information about the CSV columns see the JSON route

Trades History

import requests

endpoint = '%s/user/trades?start=%s&end=%s' % (base, start, end)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve their trade activity This route takes the following optional query parameters:

Parameter Type Description
accountId string Account UUID that the user has access to (can be retrieved with the /user route)
mpid string 4-character Market participant ID that the user has access to (can be retrieved with the /user route). If supplied, overwrites the account parameter.
asset string Asset filter
token string Order id filter
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
order string The sort order (by time), can be "asc" or "desc" (defaults to "asc") (Only used with pagination)
virtualAccountId number Specific virtual account to retrieve trades for (defaults to null)

One of start and end MUST be provided (both can be provided at once).

HTTP Request

GET /user/trades

If pagination is not used, results will be streamed as chunks of JSON objects (using the transfer-encoding header)
This is the prefered way of getting large amount of records at once, but be aware that this may present long wait before the query fully finishes.

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "time": "2021-01-06T13:41:55.348Z",
      "mpid": "SHLD",
      "orderId": "3061388281894476",
      "mid": "864691128455135233",
      "side": "Buy",
      "asset": "BTC",
      "currency": "USDT",
      "volume": "1.1001",
      "price": "18000.43",
      "total": "19997.429914",
      "liquidity": "Make",
      "venue": "Binance",
      "virtualAccountId": null,
      "assetName": "BTC"
    }
  ],
  "count": 129
}

Where data is a JSON array of objects with the following properties:

Header Type Description
time Date ISO date of Trade execution
mpid string 4-character Market participant ID
orderId string Unique token supplied at order creation
mid string Match ID
side string "Sell" or "Buy"
asset string Asset identifier
currency string Currency identifier
volume string Traded volume
price string Price of traded volume (0 indicates failed execution)
total string Total volume of currency for this trade
liquidity string "Make" or "Take"
venue string The venue this trade executed on
virtualAccountId number Virtual account id (null indicates the "Main Account")
assetName string Human readable asset name (for SPOT assets, it is identical to the asset property)

Trades history report

import requests

endpoint = '%s/user/trades/report?start=%s&end=%s' % (base, start, end)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve a CSV report of their trade activity The returned data is not ordered in any way for performance reasons. (Except if pagination is used)
This route takes the same optional query parameters as the JSON route except it doesn't support pagination.

HTTP Request

GET /user/trades/report

Response fields

Example CSV file returned by the request:

  Time,MPID,OrderId,MatchId,Side,Asset,Currency,Volume,Price,Venue,Total,Liquidity,Virtual Account Id,Asset Name
  2021-01-06T13:41:55.348Z,SHLD,3061388281894476,98725452,Buy,BTC,USDT,1.1001,18000.43,Binance,19997.429914,Make,,BTC

For information about the CSV columns see the JSON route

Dust Conversions

import requests

endpoint = '%s/user/dust-conversions?start=%s&end=%s' % (base, start, end)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve their dust conversion history This route takes the following optional query parameters:

Parameter Type Description
accountId string Account UUID that the user has access to (can be retrieved with the /user route)
asset string Asset filter
start number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
end number or string inclusive Can be either a Unix timestamp (in seconds), a JS timestamp (in milliseconds), or a string date with format YYYY-MM-DD HH:mm:ss or YYYY-MM-DDTHH:mm:ss.SSSZ
order string The sort order (by time), can be "asc" or "desc" (defaults to "asc") (Only used with pagination)
virtualAccountId number Specific virtual account to retrieve trades for

HTTP Request

GET /user/dust-conversions

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "createdAt": "2021-01-06T13:41:55.348Z",
      "requestId": "71c60afa-4013-55b7-b7e1-ee1a34322e49",
      "subAccount": "funding",
      "side": "Sell",
      "assetId": "BTC",
      "currencyId": "USDT",
      "volume": "1.1001",
      "price": "18000.43",
      "total": "19997.429914",
      "liquidity": "Take",
      "virtualAccountId": null
    }
  ],
  "count": 12
}

Where data is a JSON array of objects with the following properties:

Header Type Description
createdAt Date ISO date of dust conversions
requestId string UUID of the conversion request
subAccount string "funding"
side string "Sell" or "Buy"
assetId string Asset identifier
currencyId string Currency identifier
volume string Volume Converted
price string Price of converted volume
total string Total volume of currency for this conversion
liquidity string "Make" or "Take"
virtualAccountId number Virtual account id (null indicates the "Main Account")

Dust Conversions Report

import requests

endpoint = '%s/user/dust-conversions/report?start=%s&end=%s' % (base, start, end)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve a CSV report of their dust conversion history This route takes the same optional query parameters as the JSON route except it doesn't support pagination.

HTTP Request

GET /user/dust-conversions/report

Response fields

Example CSV file returned by the request:

  Time,Request ID,Sub Account,Side,Asset,Currency,Volume,Price,Total,Liquidity,Virtual Account ID
  2021-01-06T13:41:55.348Z,b8475026-52fe-5e40-afae-4203621d66b9,funding,Sell,BTC,USDT,1.1001,18000.43,19997.429914,Make,

For information about the CSV columns see the JSON route

Market Data Websocket

Data Websocket Usage

Aplo gathers market data from all the venues it is connected to and provide a real-time market data feed to its customers.

Data General

Production Websocket URL: wss://sheeldmatch.com:6443/

UAT Websocket URL: wss://uat.sheeldmatch.com:6443/

Authenticate using an API key HTTP header upon connecting

The server WILL disconnect every client that:

  1. does not send handshake HTTP request within 10s after opening the connection.
  2. does not answer with a pong frame to a ping frame sent by the server within 10 seconds.

Useful ressources

Websocket Protocol Documentation: https://tools.ietf.org/html/rfc6455
Websocket in Python: https://pypi.org/project/websocket-client/
Websocket in JavaScript: https://javascript.info/websocket
JSON Format Documentation: https://www.json.org/json-en.html

Data Messages Format

Server behavior

Every websocket frame sent by the server WILL be a text frame containing one JSON object as described in the JSON format. No compression of any kind WILL be used.

The JSON object WILL contain the following JSON key with their associated JSON values:

Key Value
type one of "H", "L", "B", "S", "F", "Z" or "U"

Every client is guaranteed to receive every message. A slow client will be dropped by the server.

Client rules

The client MUST NOT send any websocket frame to the server. Subscriptions are done with url parameters (max 50 subscriptions per connection). Failure to comply will lead to disconnection of the client by the server.

Data Subscription

Subscription is done through url parameters. The client CANNOT directly unsubscribe and will need to close the websocket before opening it again with other url parameters.

wsurl="wss://sheeldmatch.com:6443/?depth=10&symbols=BTC-USDT.SPOT@Binance/ETH-USDT.SPOT@KuCoin"

The accepted parameters are the following:

Paramater Rule Default Value
depth Optional 1 one of 0, 1, 10, 25
symbols Mandatory None a list of form instrument1@venue1/instrument2@venue2/... where venue1, venue2 ... and intrument1, intrument2, ... are described in universe

Subscribe to depth:

Snapshots are sent every 100ms. Trades are sent as soon as execution happens.

Trades Messages

{
    "type": "H",
    "venue": "Binance",
    "instrument": "BTC-USDT.SPOT",
    "data": [
        {
            "price": 100000.0,
            "volume": 1.0,
            "time": "2021-04-27T06:08:28.936000000Z"
        },
        ...
    ]
}
Key Value Type Description
type string H for "hit the bid" (buyer is maker) OR L for "lift the offer" (seller is maker)
venue string name of the subscribed venue
instrument string name of the subscribed instrument
data → price number price at which the trade was executed
data → volume number volume of the execution
data → time string ISO8601 time format of the timestamp at which the execution happend

Order-Book Messages

{
    "type": "B",
    "venue": "Binance",
    "instrument": "BTC-USDT.SPOT",
    "data": [
        {
            "depth": 0,
            "price": 100000.0,
            "volume": 1.0,
            "time": "2021-04-27T06:08:28.936000000Z"
        },
        {
            "depth": 1,
            "price": 100000.0,
            "volume": 1.0,
            "time": "2021-04-27T06:08:28.936000000Z"
        },
        ...
    ]
}
Key Value Type Description
type string B if bids need to be updated OR S if asks need to be updated
venue string name of the subscribed venue
instrument string name of the subscribed instrument
data → depth number depth of the orderbook level to update
data → price number new price of the level that replaces the old one
data → volume number new volume of the level that replaces the old one
data → time string ISO8601 time format of the timestamp at which the order-book modification happend

For each message, the client will have to forget ALL the old levels for the given venue and instrument, and consider the new ones. Empty data array means that there is no more levels in the orderbook (may happen when Aplo loses connexion to the exchanges).

A snapshot will be pushed on connection, and then the client will receive new snapshots every 100ms should any level within the subscribed depth change.

Sequence-is-over Messages

{
  "type": "Z",
  "data": []
}
Key Value Type Description
type string Z for sequence is over message type

Order-book data being sent every 100ms, the client sometimes needs to know when all order-book messages have been sent accross all venues and instruments for the current period.

The "sequence-is-over" message serves this purpose.

Micro-Structure Messages

{
  "type": "U",
  "venue": "Binance",
  "instrument": "BTC-USDT.SPOT",
  "data": [
    {
      "lot": 2,
      "tick": 4,
      "time": "2021-04-27T06:08:28.936000000Z"
    }
  ]
}
Key Value Type Description
type string U for micro-structure type
venue string name of the subscribed venue
instrument string name of the subscribed instrument
data → lot number number of decimals allowed by external venues for order volume
data → tick number number of decimals allowed by external venues for order price
data → time string ISO8601 time format of the timestamp at which the last check was done

Micro-Structure Messages are published as soon as the client subscribes to depth >= 0 for a given instrument on a given external venue (e.g. Binance).

They are published every 10 seconds.

Funding Rate Messages

{
  "type": "F",
  "instrument": "BTC-USDT.SPOT",
  "data": [
    {
      "funding_rate": 0.00025,
      "settlement": "2021-04-27T08:00:00.000000000Z",
      "time": "2021-04-27T06:08:28.936000000Z"
    }
  ]
}
Key Value Type Description
type string F for funding rate type
instrument string name of the subscribed instrument
data → funding_rate number the current estimated funding rate for the current period
data → time string ISO8601 time format of the timestamp at which the last estimated funding rate was retrieved
data → settlement string ISO8601 time format of the timestamp at which the settlement will happen

Funding Rate Messages are published as soon as the client subscribes to depth >= 0 for a perpetual instrument.

They are specific to an instrument.

They are published every 1 second.

Trading Websocket

Trading Websocket Usage

Aplo offers a low-latency and optimized trading environment. However, connections to external venues can sometimes increase the native latency and requests may timeout (especially posting Immediate-or-Cancel Routed orders).

Trading General

Production Websocket URL: wss://sheeldmatch.com:9443/json

UAT Websocket URL: wss://uat.sheeldmatch.com:9443/json

Authenticate using an API key HTTP header upon connecting

The server WILL disconnect every client that:

  1. does not send a ping frame (see RFC) to the server at most every 60 seconds.
  2. does not answer with a pong frame to a ping frame sent by the server within 5 seconds.

Useful ressources

Websocket Protocol Documentation: https://tools.ietf.org/html/rfc6455
Websocket in Python: https://pypi.org/project/websocket-client/
Websocket in JavaScript: https://javascript.info/websocket
JSON Format Documentation: https://www.json.org/json-en.html

Trading Messages Format

Server behavior

Every websocket frame sent by the server WILL be a text frame containing one JSON object as described in the JSON format. No compression of any kind WILL be used.

The JSON object WILL contain the following JSON key with its associated JSON value:

Key Value
type one of "O" for Order, "T" for Trade, "B" for Balance, "S" for Risk, "V" for Venues OR "I" for Instruments

For the same type, JSON objects sent by the server WILL always have the same structure with the same JSON keys. A message sent by the server to the client is called a response. The structure of every response is described throughout this documentation.

Client behavior

Every websocket frame sent by the client WILL be a text frame containing one JSON object as described in the JSON format. No compression of any kind WILL be used.

The JSON object MUST contain the following JSON key with its associated JSON value:

Key Value
type one of "A" to Add, "D" to Reduce, "M" to Modify OR "R" to Remove

For the same type, JSON objects sent by the client MUST always have the same structure with the same JSON keys. A message sent by the client to the server is called a request. The structure of every request is described throughout this documentation.

Failure to comply to any MUST rule will lead to the disconnection of the client by the server.

Trading Subscription

Subscription is done through url parameters. The client CANNOT directly unsubscribe and will need to close the websocket before opening it again with other url parameters.

The client can subscribe to one or multiple MPIDs. A client which is subscribed to one MPID will received every request and every response about every order belonging to this MPID.

A client CANNOT subscribe to MPIDs it is not authorized to trade through. For more information about authorized MPIDs, please contact support.

wsurl="wss://sheeldmatch.com:9443/json?mpids=ABCD/EFGH/IJKL"

The accepted parameters are the following:

Paramater Rule Default Value
mpids Mandatory None a list of form mpid1/mpid2/... where mpid1, mpid2, ... are MPIDs the client is authorized to trade through

Authentification

Authentification is done the same way as for the REST API (see Authenticate each Request). The Authorization header has to be put in the headers of the websocket handshake HTTP request.

Add Request

Orders type are further described in Trading.

{
  "type": "A",
  "mpid": "ABCD",
  "virtual_id": "0",
  "token": "109298439784",
  "instrument": "BTC-USDT.SPOT",
  "price": "100000.01",
  "volume": "100.5",
  "side": "S",
  // smart order routing (SOR)
  "parameters": {
    "type": "IDO", // or ISO, IGO, IPO, MDO, MSO, MGO, MPO
    "priority": "price" // or time, both
  },
  // OR direct strategy access (DSA)
  "parameters": {
    "type": "VIO",
    "participation": "50" // in percentage
  },
  // OR direct strategy access (DSA)
  "parameters": {
    "type": "TWAP", // or VWAP
    "lifespan": "100" // minutes
  },
  // OR tailor-made order (TMO)
  "parameters": {
    "type": "VTO",
    "stop": "90000.1" // limit volume
  },
  "parameters": {
    "type": "SLO", // or TPO
    "stop": "90000.1", // limit price
    "anchor": "mid" // or bid, offer, last
  },
  // OR direct market access (DMA)
  "parameters": {
    "type": "IOC", // or DAY, GTC, POD, FOK
    "venue": "Binance"
  },
  // Can be empty if no parameters are needed
  "parameters": {
    "type": "PTO" // or IMSH
  }
}
Key Value Type Description
type string A
mpid string the mpid placing the order
virtual_id string the Virtual Account Id placing the order, "0" for the "Main Account"
token string the token of the order (must be unique accross all orders passed by one MPID)
instrument string name of the instrument as described in universe
price string price of the order (MUST be omitted for "MKT" and "DCA" orders)
volume string volume of the order (MUST be omitted for parameters.notional orders)
side string side of the order
parameters → type string type of the order, must be one of "IDO", "ISO", "IGO", "IPO", "MDO", "MSO", "MGO", "MPO", "VIO", "POV", "FAT", "TWAP", "VWAP", "SLO", "TPO", "VTO", "IOC", "DAY", "GTC", "POD", "FOK", "PTO", "LMT", "MKT" or "DCA"
parameters → priority string ONLY FOR "ISO", "IGO", "IPO", "MDO", "MSO", "MGO" or "MPO". One of "price" for price priority, "time" for time priority OR "both" for price/time priority
parameters → lifespan string ONLY FOR "TWAP" or "VWAP. Lifespan in minutes. Accepted range 1 - 525600
parameters → participation string ONLY FOR "VIO". Participation in percentage. Accepted range 1 - 99
parameters → stop string ONLY FOR "VTO", "SLO" or "PTO" . Stop price (or volume for "VTO")
parameters → anchor string ONLY FOR "SLO" or "TPO". One of "mid" for mid price anchor, "bid" for best bid price anchor, "offer" for best offer price anchor or "last" for last exec price anchor.
parameters → venue string ONLY FOR "IOC", "DAY", "GCT", "FOK" or "POD". Direct market access to this venue (name described in universe)
parameters → start string ONLY FOR "DCA". Start of execution, paired with parameters.frequency. Format MUST be YYYY-MM-DD
parameters → frequency string ONLY FOR "DCA". Frequency of execution. Must be "daily", "weekly" or "monthly", see here for details
parameters → volume string ONLY FOR "DCA". Volume of each execution (see parameters.frequency)
parameters → notional string ONLY FOR "MKT", "LMT" or "DCA". Notional for the order (or notional for each execution for "DCA")

Remove request

{
  "type": "R",
  "mpid": "ABCD",
  "virtual_id": "9812441",
  "token": "109298439784"
}
Key Value Type Description
type string R
mpid string the mpid that placed the order
virtual_id string the Virtual Account Id that placed the order, "0" for the "Main Account"
token string the token of the order (must be unique accross all orders passed by one MPID)

Modify Request

{
  "type": "M",
  "mpid": "ABCD",
  "virtual_id": "9812441",
  "token": "109298439784",
  "price": "100000.01",
  "instrument": "BTC-USDT.SPOT",
  "volume": "100.5"
}
Key Value Type Description
type string M
mpid string the mpid that placed the order
virtual_id string the Virtual Account Id that placed the order, "0" for the "Main Account"
token string the token of the order (must be unique accross all orders passed by one MPID)
instrument string instrument of the order
price string new price of the order
volume string new volume of the order

Reduce Request

{
  "type": "D",
  "virtual_id": "4123",
  "mpid": "ABCD",
  "token": "109298439784",
  "instrument": "BTC-USDT.SPOT",
  "volume": "100.5"
}
Key Value Type Description
type string D
mpid string the mpid that placed the order
virtual_id string the Virtual Account Id that placed the order, "0" for the "Main Account"
token string the token of the order (must be unique accross all orders passed by one MPID)
instrument string instrument of the order
volume string new volume of the order (MUST be lower than the old volume)

Order Response

The client will receive this kind of response:

The purpose of this message is to reflect the state of the order associated to the MPID/token pair given in the response. On status error, the response is not guaranteed to be representative of the state of any order.

{
  "type": "O",
  "mpid": "ABCD",
  "virtual_id": "0",
  "token": "109298439784",
  "instrument": "BTC-USDT.SPOT",
  "venue": "",
  "side": "S",
  "price": "100000.01",
  "volume": "100.5",
  "time": "2021-06-21T13:09:51.950717685Z",
  "creation_time": "2021-06-20T11:34:12.982647564Z",
  "status": "ok",
  "reason": "Add: Success",
  "executed_volume": "0",
  "executed_total": "0",
  "execution_count": "0"
}
Key Value Type Description
type string O
mpid string the mpid that placed the order
virtual_id string the Virtual Account Id that placed the order, "0" for the "Main Account"
token string the token of the order (must be unique accross all orders passed by one MPID)
instrument string name of the instrument as described in universe
venue string name of the venue as described in universe. May be empty for order type other than DMA
price string price of the order (can be null for "MKT" and "DCA" orders)
volume string remaining volume of the order. 0 means the order is closed ("null" for orders using parameters.notional)
side string side of the order
time string time of the update in ISO8601 format with nanoseconds precision (YYYY-mm-ddTHH-MM-SS.NNNNNNNNNZ)
creation_time string time of the initial order creation in ISO8601 format with nanoseconds precision (YYYY-mm-ddTHH-MM-SS.NNNNNNNNNZ)
status string one of "ok" OR "error"
reason string reason explaining why the client received the order update (described in Reasons)
executed_volume string Amount of volume executed
executed_total string Amount of executed currency
execution_count string Number of executions

An additional property request is present for Order responses with reason "Initialization: Open Order" that are broadcasted upon connection.
This property is a copy of the initial Add request for additional information like type, parameters, volume (requested volume) and price (requested price)

Trade Response

The client will receive this kind of response everytime an execution happens.

The purpose of this message is to give the details of the execution that just happened.

{
  "type": "T",
  "mpid": "ABCD",
  "virtual_id": "98124",
  "token": "109298439784",
  "instrument": "BTC-USDT.SPOT",
  "venue": "Binance",
  "side": "S",
  "price": "100000.01",
  "volume": "100.5",
  "time": "2021-06-21T13:09:51.950717685Z",
  "mid": "13098120498203487",
  "reason": "Execution: Normal Execution",
  "fees": "12",
  "liquidity": "maker"
}
Key Value Type Description
type string T
mpid string the mpid that placed the order
virtual_id string the Virtual Account Id that placed the order, "0" for the "Main Account"
token string the token of the order (must be unique accross all orders passed by one MPID)
instrument string name of the instrument as described in universe
venue string name of the venue on which the execution happened (name described in universe)
side string side of the associated order
price string price of the execution (can be 0 for "DCA" failed executions)
volume string executed volume
time string time of the execution in ISO8601 format with nanoseconds precision (YYYY-mm-ddTHH-MM-SS.NNNNNNNNNZ)
mid string id of the execution (64bits integer)
reason string reason detailing the execution status
fees string fees in bps
liquidity string maker, taker or unknonwn (for "DCA" failed executions)

Balance Response

The client will receive this kind of response everytime there is a change in balances and on connection, just after the handshake.

{
  "type": "B",
  "mpid": "ABCD",
  "virtual_id": "0",
  "asset_id": "BTC",
  "asset_name": "BTC",
  "reason": "execution",
  "time": "2021-06-21T13:09:51.950717685Z",
  "total": "2.0",
  "committed": "0.5",
  "collateralized": "0.5",
  "borrowed": "0",
  "available": "1",
  "total_change": "2",
  "cost": 38000,
  "position_cost": "32500",
  "accumulated": "2.5"
}
Key Value Type Description
type string B
mpid string the mpid owning this balance
virtual_id string the Virtual Account Id owning this balance, "0" for the "Main Account"
asset_id string asset id uniquely identifying the asset (may not be explicit for non spot asset)
asset_name string explicit asset name (same as asset_id for spot assets)
reason string event that led to the modification of the balance
time string time of the publication in ISO8601 format with nanoseconds precision (YYYY-mm-ddTHH-MM-SS.NNNNNNNNNZ)
total string total balance
committed string committed balance
collateralized string collateralized balance
borrowed string borrowed balance
available string available balance
total_change string change in total balance since last balance response
cost string money flow of asset
position_cost string current position cost of asset
accumulated string accumulated transacted quantity of asset

Risk Response

The client will receive this kind of response when they have margined positions open on their mpid

{
  "type": "S",
  "mpid": "ABCD",
  "virtual_id": "0",
  "asset_id": "wBTC_A",
  "asset_name": "BTC-USDT.PERP-USDT-Binance",
  "time": "2021-06-21T13:09:51.950717685Z",
  "margin_ratio_distance": "2.00000"
}
Key Value Type Description
type string S
mpid string the mpid owning this balance
virtual_id string the Virtual Account Id owning this balance, "0" for the "Main Account"
asset_id string asset id uniquely identifying the asset (may not be explicit for non spot asset)
asset_name string explicit asset name (same as asset_id for spot assets)
time string time of the publication in ISO8601 format with nanoseconds precision (YYYY-mm-ddTHH-MM-SS.NNNNNNNNNZ)
margin_ratio_distance string Liquidation risk indicator: 0 -> No Risk, 1 -> Low Risk, 2 -> Moderate Risk, 3 -> High Risk, 4 -> Very High Risk, 5 -> Liquidation in progress

End Of Sequence Response

The client will receive this response once after all the "O" and "B" (Order and Balance) initilization messages have been sent.

{
  "type": "Z"
}
Key Value Type Description
type string R

Venues Response

The client will receive this kind of response on connection, just after the handshake.

{
  "type": "V",
  "venues": ["Binance", "OKEx", "Huobi"]
}
Key Value Type Description
type string V
venues JSON array array of all venues

Instruments Response

The client will receive this kind of response on connection, just after the handshake.

{
  "type": "I",
  "instruments": ["BTC-USDT.SPOT", "ETH-USDT.SPOT", "ADA-USDT.SPOT"]
}
Key Value Type Description
type string I
instruments JSON array array of all instruments

Reasons

Every reason is formed the same way. It starts with the "why" the client received the response and ends with an explanation.

Every reason will starts with one of the following string:

String Description
"Add: " In response to an add request
"Remove: " When an order is removed
"Modify: " When an order is modified
"Reduce: " When an order is reduced
"Execution: " When an execution occurs
"Bad Request: " When a request is malformed or when type/mpid/token cannot be determined
"Initialization: " On connection

Every reason will end with an explanation that will depend on the status. For status ok please refer to OK Reasons. For status error please refer to Error Reasons.

The reason for the order responses broadcasted on connection will be "Initialization: Open Order".

OK Reasons

Explanation Description
"Success" The request was successful
"Normal Execution" A normal execution happened
"Busted Execution" The execution has been busted
"Self Execution" A self execution happened
"Removed due to expiration" An order expired
"Removed by market supervision" An order is removed by market supervision
"Removed by the System (at the end of the day session)" An order is removed because end of day is reached
"Removed by the Matching Engine" An order is removed by the matching engine
"Open Order" The order was open before connection

Error Reasons

Explanation Description
"Temporarily Unavailable" Try again later
"Time-In-Force Expiry" When an order expires due to Time-In-Force concerns
"Insufficient Balance" Balance is insufficient
"Limit breach" Limits defined in backoffice have beend reached
"Bad Market Participant ID" MPID is unknown, unauthorized or unsubscribed
"Bad Instrument" Instrument is unknown or not allowed to trade
"Bad Token or Dead Order" Token is either unknown for this mpid or belongs to an already known order (for add) or already closed order (for remove/modify/reduce)
"Bad Price" Price is malformed or does not respect tick or was not accepted by external platform
"Race Condition" Previous request for this pair MPID/token has not been responded yet. The client must wait for the response before sending request again.
"Bad Side" Side is malformed (must be B or S)
"Bad Volume" Volume is malformed or does not respect lot or was not accepted by external platform
"Bad Notional" Notional is malformed or does not respect lot/tick or was not accepted by external platform
"General failure" Something unexpected happened
"Bad Venue" Venue is unknown
"Market not open" Market is not opened
"One of type, mpid or token is missing or wrong" Could not identify type/mpid/token in request
"Bad parameter type for Direct Market Access" Parameter type in add request is wrong for DMA
"Bad parameter stop for Tailor-Made Order" Parameter stop in add request is wrong for TMO
"Bad parameter stop for Volume Triggered Order" Parameter stop in add request is wrong for VTO
"Bad parameter stop for Stop Loss Order" Parameter stop in add request is wrong for SLO
"Bad parameter stop for Take Profit Order" Parameter stop in add request is wrong for TPO
"Bad parameter participation for Volume Inline Order" Parameter participation in add request is wrong for VIO
"Bad parameter type for Direct Strategy Access" Parameter type in add request is wrong for DSA
"Bad parameter lifespan for Time Weighted Average Price Order" Parameter lifespan in add request is wrong for TWAP
"Bad parameter lifespan for Volume Weighted Average Price Order" Parameter lifespan in add request is wrong for VWAP
"Bad parameter type for Smart Order Routing" Parameter type in add request is wrong for SOR
"Bad parameter priority for Smart Order Routing" Parameter priority in add request is wrong for SOR
"Bad parameters" Bad parameters for the request type
"Unknown Type" Unknown request type

Price Feed

General usage

Aplo gathers market data from all the venues it is connected to and its quoting engine generates quotes for volumes requested by customers. Quotes can then be executed using the dedicated route using a Fill-Or-Kill order.

Production Websocket URL: wss://sheeldmatch.com:5443?mpid=ABCD

UAT Websocket URL: wss://uat.sheeldmatch.com:5443?mpid=ABCD

Authenticate using an API key HTTP header upon connecting

The server WILL disconnect every client that:

  1. does not send handshake HTTP request within 10s after opening the connection.
  2. does not subscribe to anything within 10s after handshake (trick: send empty subscription message to bypass this timeout while being subscribed to nothing).
  3. does not answer with a pong frame to a ping frame sent by the server within 10 seconds.

Every websocket frame sent by the server WILL be a text frame containing one JSON object as described in the JSON format. No compression of any kind WILL be used.
Every client is guaranteed to receive every message. A slow client will be dropped by the server.

The accepted parameters are the following:

Paramater Rule Default Value
mpid Mandatory None a single mpid authorized to get the feed

Useful ressources

Websocket Protocol Documentation: https://tools.ietf.org/html/rfc6455
Websocket in Python: https://pypi.org/project/websocket-client/
Websocket in JavaScript: https://javascript.info/websocket
JSON Format Documentation: https://www.json.org/json-en.html

Subscription Messages

Subscribe event:

# Example of request
{
    "event": "subscribe",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
            }
        ]
}

# Example of successful response
{
    "event": "subscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "success": true,
                "error": ""
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-28-01T00:00:00Z"
}

# Example of partially successful response
{
    "event": "subscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.598943",
                "success": false,
                "error": "Bad Volume"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

# Example of already subscribed quotes
{
    "event": "subscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "success": false,
                "error": "already subscribed"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "success": false,
                "error": "already subscribed"
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Unsubscribe event:

# Example of request
{
    "event": "unsubscribe",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000"
            }
        ]
}

# Example of response
{
    "event": "unsubscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "success": true,
                "error": ""
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Resubscribe event:

# Example of request
{
    "event": "resubscribe",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000"
            }
        ]
}

# Example of response
{
    "event": "resubscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "success": true,
                "error": ""
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

A subscription request JSON MUST contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribe", "unsubscribe" OR "resubscribe"
quotes a list of quote requests

The subscribe event

The subscribe event is designed to subscribe to quote feeds. This event can be used multiple times to accumulate subscriptions into a connection. Subscription requests for already subscribed quotes are ignored.

The unsubscribe event

The unsubscribe event is designed to unsubscribe to specific quote feeds. This event can be used multiple times to remove subscriptions from a connection.

The resubscribe event

The resubscribe event is designed to unsubscribe to all currently subscribed quote feeds and subscribe to new feeds.

A quote subscription request is defined by the following parameters:

Parameter Rule Value
instrument Mandatory one of the instruments described in universe
side Mandatory can be "buy" or "sell"
volume Optional volume of the quote
notional Optional notional value of the quote

Only one of notional or volume NEEDS to be specified for every quote.

Sending a notional value creates a subscription that will have its quoted volume and price change to match the given notional value.


A subscription response JSON WILL contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribed", "unsubscribed" OR "resubscribed"
quotes a list of quote responses
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A quote subscription response is defined by the following parameters:

Parameter Value
instrument one of the instruments described in universe
side can be "buy" or "sell"
volume volume of the quote (or empty when quoting notional)
notional notional of the quote (or empty when quoting volume)
success can be true or false
error error description if any

Quote Feed Messages

{
  "event": "feed",
  "quotes": [
    {
      "instrument": "BTC-USDT.SPOT",
      "side": "buy",
      "volume": "10.5",
      "notional": "316001.7",
      "price": "30095.4"
    },
    {
      "instrument": "BTC-USDT.SPOT",
      "side": "sell",
      "volume": "4.9840",
      "notional": "150000",
      "price": "30095.9"
    }
  ],
  "success": true,
  "error": "",
  "timestamp": 1643359449830582000,
  "iso_timestamp": "2022-01-01T00:00:00Z"
}

When subscribed to quote feeds, quotes are regularly updated through push messages. A message contains only the updated quotes. Unchanged quotes are absent from the message.

A push JSON quote WILL contain the following JSON keys with their associated JSON values:

Key Value
event "feed"
quotes a list of quotes
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A quote is defined by the following parameters:

Parameter Value
instrument one of the instruments described in universe
side can be "buy" or "sell"
volume volume of the quote
notional notional of the quote (volume * price)
price price of the quote

Depending on whether you provide notional or volume, the other side will be computed based on the given quote price.

Execute a Quote

Executing a quote corresponds to sending a Fill-Or-Kill (FOK) order with the price and volume of the quote received from the price feed. A FOK order cannot be partially executed. If the FOK order is sent before receiving an updated quote, the order is likely to be fully filled in a single execution. If the order is sent too late, the order may expire without any fills.

The interaction with this route follows the guidelines documented in the Trading section.

HTTP Request

POST /participants/:mpid/quotes/fok

import requests

endpoint = '%s/participants/%s/quotes/fok' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "11052.59"
       }
response = requests.post(endpoint, headers=headers, json=body)

This endpoint requires the following parameters:

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy", "sell"
volume string Quote size
price string Quote price

Full Book Subscription Messages

Subscribe event:

# Example of request
{
    "event": "subscribe",
    "books": [
        "BTC-USDT.SPOT",
        "ETH-USDT.SPOT"
    ]
}

# Example of successful response
{
    "event": "subscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": true,
                "error": ""
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-28-01T00:00:00Z"
}

# Example of partially successful response
{
    "event": "subscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": false,
                "error": "already subscribed"
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Unsubscribe event:

# Example of request
{
    "event": "unsubscribe",
    "books": [
        "BTC-USDT.SPOT",
        "ETH-USDT.SPOT"
    ]
}

# Example of response
{
    "event": "unsubscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": true,
                "error": ""
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Resubscribe event:

# Example of request
{
    "event": "resubscribe",
    "books": [
        "BTC-USDT.SPOT",
        "ETH-USDT.SPOT"
    ]
}

# Example of response
{
    "event": "resubscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": true,
                "error": ""
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Additionally, it is possible to directly access the orderbook used to derive quotes through the books feed.

A subscription request JSON MUST contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribe", "unsubscribe" OR "resubscribe"
books a list of instruments described in universe

The subscribe event

The subscribe event is designed to subscribe to book feeds. This event can be used multiple times to accumulate subscriptions into a connection. Subscription requests for already subscribed books are ignored.

The unsubscribe event

The unsubscribe event is designed to unsubscribe to specific book feeds. This event can be used multiple times to remove subscriptions from a connection.

The resubscribe event

The resubscribe event is designed to unsubscribe to all currently subscribed book feeds and subscribe to new feeds.


A subscription response JSON WILL contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribed", "unsubscribed" OR "resubscribed"
books a list of book responses
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A book subscription response is defined by the following parameters:

Parameter Value
instrument one of the instruments described in universe
success can be true or false
error error description if any

Full Book Feed Messages

{
    "event": "feed",
    "books": [
        {
            "type": "B",
            "instrument": "BTC-USDT.SPOT",
            "data": [
                {
                    "depth": 0,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                {
                    "depth": 1,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                ...
            ]
        },
        {
            "type": "S",
            "instrument": "BTC-USDT.SPOT",
            "data": [
                {
                    "depth": 0,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                {
                    "depth": 1,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                ...
            ]
        },
        ...
    ],
    "success": true,
    "error": "",
    "timestamp": 1643359449830582000,
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

When subscribed to book feeds, books are regularly updated through push messages.

A push JSON book WILL contain the following JSON keys with their associated JSON values:

Key Value
event "feed"
books a list of book objects
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A book object is defined by the following parameters:

Key Value Type Description
type string B if bids need to be updated OR S if asks need to be updated
instrument string name of the subscribed instrument
data → depth number depth of the orderbook level to update
data → price number new price of the level that replaces the old one
data → volume number new volume of the level that replaces the old one

Price Stream Orders

Websocket usage

Aplo gathers market data from all the venues it is connected to and its quoting engine generates quotes for volumes requested by customers. Quotes can then be executed using the dedicated route using a Fill-Or-Kill order.

Production Websocket URL: wss://sheeldmatch.com:5443?mpid=ABCD

UAT Websocket URL: wss://uat.sheeldmatch.com:5443?mpid=ABCD

Authenticate using an API key HTTP header upon connecting

The server WILL disconnect every client that:

  1. does not send handshake HTTP request within 10s after opening the connection.
  2. does not subscribe to anything within 10s after handshake (trick: send empty subscription message to bypass this timeout while being subscribed to nothing).
  3. does not answer with a pong frame to a ping frame sent by the server within 10 seconds.

Every websocket frame sent by the server WILL be a text frame containing one JSON object as described in the JSON format. No compression of any kind WILL be used.
Every client is guaranteed to receive every message. A slow client will be dropped by the server.

The accepted parameters are the following:

Paramater Rule Default Value
mpid Mandatory None a single mpid authorized to get the feed

Useful ressources

Websocket Protocol Documentation: https://tools.ietf.org/html/rfc6455
Websocket in Python: https://pypi.org/project/websocket-client/
Websocket in JavaScript: https://javascript.info/websocket
JSON Format Documentation: https://www.json.org/json-en.html

Subscription Message

Subscribe event:

# Example of request
{
    "event": "subscribe",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0.0001"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0.0005"
            }
        ]
}

# Example of successful response
{
    "event": "subscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0.0001",
                "success": true,
                "error": ""
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0.0005",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-28-01T00:00:00Z"
}

# Example of partially successful response
{
    "event": "subscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.598943",
                "markup": "0",
                "success": false,
                "error": "Bad Volume"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.3",
                "markup": "23",
                "success": false,
                "error": "Markup out of range"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

# Example of already subscribed quotes
{
    "event": "subscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0",
                "success": false,
                "error": "already subscribed"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "markup": "0",
                "notional": "150000",
                "success": false,
                "error": "already subscribed"
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Unsubscribe event:

# Example of request
{
    "event": "unsubscribe",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0.0042"
            }
        ]
}

# Example of response
{
    "event": "unsubscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0",
                "success": true,
                "error": ""
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0.0042",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Resubscribe event:

# Example of request
{
    "event": "resubscribe",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0.001"
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0.087"
            }
        ]
}

# Example of response
{
    "event": "resubscribed",
    "quotes":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "buy",
                "volume": "10.5",
                "markup": "0.001",
                "success": true,
                "error": ""
            },
            {
                "instrument": "BTC-USDT.SPOT",
                "side": "sell",
                "notional": "150000",
                "markup": "0.0087",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

A subscription request JSON MUST contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribe", "unsubscribe" OR "resubscribe"
quotes a list of quote requests

The subscribe event

The subscribe event is designed to subscribe to quote feeds. This event can be used multiple times to accumulate subscriptions into a connection. Subscription requests for already subscribed quotes are ignored.
You can have multiple subscription for the same side/volume/notional but each with a different markup.

The unsubscribe event

The unsubscribe event is designed to unsubscribe to specific quote feeds. This event can be used multiple times to remove subscriptions from a connection.

The resubscribe event

The resubscribe event is designed to unsubscribe to all currently subscribed quote feeds and subscribe to new feeds.

A quote subscription request is defined by the following parameters:

Parameter Rule Value
instrument Mandatory one of the instruments described in universe
side Mandatory can be "buy" or "sell"
volume Optional volume of the quote
notional Optional notional value of the quote
markup Optional Markup automatically applied to quote prices.
Default:0, Max:0.1, Max precision:0.0001

Only one of notional or volume NEEDS to be specified for every quote.

Sending a notional value creates a subscription that will have its quoted volume and price change to match the given notional value.


A subscription response JSON WILL contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribed", "unsubscribed" OR "resubscribed"
quotes a list of quote responses
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A quote subscription response is defined by the following parameters:

Parameter Value
instrument one of the instruments described in universe
side can be "buy" or "sell"
volume volume of the quote (or empty when quoting notional)
notional notional of the quote (or empty when quoting volume)
markup markup of the quote
success can be true or false
error error description if any

Quote Feed Message

{
  "event": "feed",
  "quotes": [
    {
      "instrument": "BTC-USDT.SPOT",
      "side": "buy",
      "volume": "10.5",
      "notional": "316001.7",
      "price": "30095.4"
    },
    {
      "instrument": "BTC-USDT.SPOT",
      "side": "sell",
      "volume": "4.9840",
      "notional": "150000",
      "price": "30095.9"
    }
  ],
  "success": true,
  "error": "",
  "timestamp": 1643359449830582000,
  "iso_timestamp": "2022-01-01T00:00:00Z"
}

When subscribed to quote feeds, quotes are regularly updated through push messages. A message contains only the updated quotes. Unchanged quotes are absent from the message.

A push JSON quote WILL contain the following JSON keys with their associated JSON values:

Key Value
event "feed"
quotes a list of quotes
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A quote is defined by the following parameters:

Parameter Value
instrument one of the instruments described in universe
side can be "buy" or "sell"
volume volume of the quote
notional notional of the quote (volume * price)
price price of the quote (markup included)

Depending on whether you provide notional or volume, the other side will be computed based on the given quote price.

Executing a Quote: Market Order

A Market Order will execute the requested volume or notional amount at current market price.
It is recommended to use the Price-Stream subscriptions in order to get up-to-date prices before sending a Market Order.

Due to market microstructure and volume precision constraints, notional orders will almost never be fully filled, though they will never overfill.

Any markup is incorporated in the execution price. For that reason, make sure that you use the same markup you may have used in the price-stream subscriptions.

The takeProfitTriggerPrice and stopLossTriggerPrice optional parameters lets you choose a trigger price before the order goes live.

For takeProfitTriggerPrice:

For stopLossTriggerPrice:

The interaction with this route follows the guidelines documented in the Trading section.

HTTP Request

POST /participants/:mpid/orders/pso/mkt

import requests

endpoint = '%s/participants/%s/orders/pso/mkt' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "markup": "0.0012"
       }
response = requests.post(endpoint, headers=headers, json=body)

This endpoint requires the following parameters:

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy", "sell"
volume string optional Quote volume
notional string optional Quote notional
markup string optional Quote markup
Default:0, Max:0.1, Max precision:0.0001
stopLossTriggerPrice string optional Stop loss trigger price
takeProfitTriggerPrice string optional Take profit trigger price

Either volume or notional need to be provided.

You cannot provide BOTH stopLossTriggerPrice and takeProfitTriggerPrice.

Executing a Quote: Limit Order

A Limit Order will execute the requested volume or notional amount with a given limit price.
It is recommended to use the Price-Stream subscriptions in order to get up-to-date prices before sending a Limit Order.

Due to market microstructure and volume precision constraints, notional orders will almost never be fully filled, though they will never overfill.

Any markup is incorporated in the execution price. For that reason, make sure that you use the same markup you may have used in the price-stream subscriptions.

The takeProfitTriggerPrice and stopLossTriggerPrice optional parameters lets you choose a trigger price before the order goes live.

For takeProfitTriggerPrice:

For stopLossTriggerPrice:

The interaction with this route follows the guidelines documented in the Trading section.

HTTP Request

POST /participants/:mpid/orders/pso/lmt

import requests

endpoint = '%s/participants/%s/orders/pso/lmt' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "price": "107935.23",
         "timeInForce": "FOK",
         "markup": "0.0012"
       }
response = requests.post(endpoint, headers=headers, json=body)

This endpoint requires the following parameters:

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy", "sell"
volume string optional Quote volume
notional string optional Quote notional
price string Quote price
timeInForce string "FOK", "GTC" or "IOC", see below for details
markup string optional Quote markup
Default:0, Max:0.1, Max precision:0.0001
stopLossTriggerPrice string optional Stop loss trigger price
takeProfitTriggerPrice string optional Take profit trigger price

Either volume or notional need to be provided.

You cannot provide BOTH stopLossTriggerPrice and takeProfitTriggerPrice.

The timeInForce parameter specifies the order's behaviour upon submission:

Executing a Quote: Dollar-Cost-Average Order

A Dollar-Cost-Average Order will execute a requested volume or notional amount using market price at regular interval with a specified frequency.

Due to market microstructure and volume precision constraints, notional orders will almost never be fully filled, though they will never overfill.

Any markup is incorporated in the execution price.

The interaction with this route follows the guidelines documented in the Trading section.

HTTP Request

POST /participants/:mpid/orders/pso/dca

import requests

endpoint = '%s/participants/%s/orders/pso/dca' % (base, mpid)
body = {
         "token": "123456789",
         "instrument": "BTC-USDT.SPOT",
         "side": "buy",
         "volume": "15",
         "frequency": "daily",
         "start": "2025-10-01",
         "markup": "0.0012"
       }
response = requests.post(endpoint, headers=headers, json=body)

This endpoint requires the following parameters:

Body Parameters

Parameter Type Description
token string A token provided by the participant to uniquely identify the order
instrument string Instrument Name as retrieved using the /instruments route
side string "buy", "sell"
volume string optional Quote volume
notional string optional Quote notional
frequency string "daily", "weekly" or "monthly", see below for details
start string optional A date in the format YYYY-MM-DD.
markup string optional Quote markup
Default:0, Max:0.1, Max precision:0.0001

Either volume or notional need to be provided.

The frequency and start parameters are used together to control when and how often the volume/notional amount will be executed.

Order will try to execute after 12 PM UTC, locates need to be allocated on the mpid used.

Here is the order behaviour regarding frequency:

Here are the edge-cases regarding the frequency and start parameters.

Frequency Start Current Date First execution Second Execution
"daily" 2025-10-31 Fri, 2015-10-31 19:00:00 UTC Sat, 2015-11-01 12:00:00 UTC Sun, 2015-11-02 12:00:00 UTC
"weekly" 2025-10-31 Fri, 2015-10-31 19:00:00 UTC Sat, 2015-11-01 12:00:00 UTC Sat, 2015-11-08 12:00:00 UTC
"monthly" 2025-10-31 Fri, 2015-10-31 19:00:00 UTC Sat, 2015-11-01 12:00:00 UTC Mon, 2015-12-01 12:00:00 UTC
"monthly" 2025-10-31 Fri, 2015-10-31 10:00:00 UTC Fri, 2015-10-31 12:00:00 UTC Sun, 2015-11-30 12:00:00 UTC

Full Book Subscription Message

Subscribe event:

# Example of request
{
    "event": "subscribe",
    "books": [
        "BTC-USDT.SPOT",
        "ETH-USDT.SPOT"
    ]
}

# Example of successful response
{
    "event": "subscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": true,
                "error": ""
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-28-01T00:00:00Z"
}

# Example of partially successful response
{
    "event": "subscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": false,
                "error": "already subscribed"
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Unsubscribe event:

# Example of request
{
    "event": "unsubscribe",
    "books": [
        "BTC-USDT.SPOT",
        "ETH-USDT.SPOT"
    ]
}

# Example of response
{
    "event": "unsubscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": true,
                "error": ""
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Resubscribe event:

# Example of request
{
    "event": "resubscribe",
    "books": [
        "BTC-USDT.SPOT",
        "ETH-USDT.SPOT"
    ]
}

# Example of response
{
    "event": "resubscribed",
    "books":
        [
            {
                "instrument": "BTC-USDT.SPOT",
                "success": true,
                "error": ""
            },
            {
                "instrument": "ETH-USDT.SPOT",
                "success": true,
                "error": ""
            }
        ],
    "success": true,
    "error": "",
    "timestamp": "1643359449830582000",
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

Additionally, it is possible to directly access the orderbook used to derive quotes through the books feed.

A subscription request JSON MUST contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribe", "unsubscribe" OR "resubscribe"
books a list of instruments described in universe

The subscribe event

The subscribe event is designed to subscribe to book feeds. This event can be used multiple times to accumulate subscriptions into a connection. Subscription requests for already subscribed books are ignored.

The unsubscribe event

The unsubscribe event is designed to unsubscribe to specific book feeds. This event can be used multiple times to remove subscriptions from a connection.

The resubscribe event

The resubscribe event is designed to unsubscribe to all currently subscribed book feeds and subscribe to new feeds.


A subscription response JSON WILL contain the following JSON keys with their associated JSON values:

Key Value
event one of "subscribed", "unsubscribed" OR "resubscribed"
books a list of book responses
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A book subscription response is defined by the following parameters:

Parameter Value
instrument one of the instruments described in universe
success can be true or false
error error description if any

Full Book Feed Message

{
    "event": "feed",
    "books": [
        {
            "type": "B",
            "instrument": "BTC-USDT.SPOT",
            "data": [
                {
                    "depth": 0,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                {
                    "depth": 1,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                ...
            ]
        },
        {
            "type": "S",
            "instrument": "BTC-USDT.SPOT",
            "data": [
                {
                    "depth": 0,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                {
                    "depth": 1,
                    "price": 100000.0,
                    "volume": 1.0,
                },
                ...
            ]
        },
        ...
    ],
    "success": true,
    "error": "",
    "timestamp": 1643359449830582000,
    "iso_timestamp": "2022-01-01T00:00:00Z"
}

When subscribed to book feeds, books are regularly updated through push messages.

A push JSON book WILL contain the following JSON keys with their associated JSON values:

Key Value
event "feed"
books a list of book objects
success can be true or false
error error description if any
timestamp time in nanoseconds
iso_timestamp time in ISO format

A book object is defined by the following parameters:

Key Value Type Description
type string B if bids need to be updated OR S if asks need to be updated
instrument string name of the subscribed instrument
data → depth number depth of the orderbook level to update
data → price number new price of the level that replaces the old one
data → volume number new volume of the level that replaces the old one

Market Analytics

The following analytics are consolidated data using our market data capture. The results may differ from other analytics tools using third party market data as Aplo may filter some data deemed incorrect and/or suspicious.

Get Analytic Universe

import requests

endpoint = '%s/analytics/universe' % (base)
response = requests.get(endpoint, headers=headers)

This route returns the current universe of available parameters for each analytic.

HTTP Request

GET /analytics/universe

Response fields

Example of JSON structure returned by the request:

{
  "trades": {
    "venue": ["Aggregated", "Huobi", "Binance"],
    "lookback": ["1d", "1w", "1m", "1y"],
    "geography": ["World", "Us", "Europe", "Asia"],
    "dayOfWeek": ["AllWeek", "Monday"]
  },
  "volume": {
    "venue": ["Aggregated", "Huobi", "Binance"],
    "lookback": ["1d", "1w", "1m", "1y"],
    "geography": ["World", "Us", "Europe", "Asia"],
    "dayOfWeek": ["AllWeek", "Monday"]
  },
  "moneyFlow": {
    "venue": ["Aggregated", "Huobi", "Binance"],
    "lookback": ["1d", "1w", "1m", "1y"],
    "geography": ["World", "Us", "Europe", "Asia"],
    "dayOfWeek": ["AllWeek", "Monday"]
  },
  "volatility": {
    "venue": ["Aggregated", "Huobi", "Binance"],
    "lookback": ["1d", "1w", "1m", "1y"],
    "geography": ["World", "Us", "Europe", "Asia"],
    "dayOfWeek": ["AllWeek", "Monday"]
  },
  "seasonality": {
    "venue": ["Aggregated", "Huobi", "Binance"],
    "lookahead": ["1d", "1w", "1m", "1y"]
  },
  "marketImpact": {
    "venue": ["Aggregated", "Huobi", "Binance"],
    "lookahead": ["1d", "1w", "1m", "1y"]
  }
}

The response is a JSON object with a key for each available analytic route and the possible values for the optional parameters they can take.

Get trades average size

import requests

endpoint = '%s/analytics/trades?instrument=%s' % (base, instrument)
response = requests.get(endpoint, headers=headers)

This analytic gives the typical size of trades of a pair on a venue based on specific lookbacks (one day, one week, one month), for a specific geography (trading hours) and a specific day in week.

This route takes the following query parameters:

Parameter Type Description
instrument string Instrument name (can be retrieved using the /instruments route)
venue string optional Venue name (default: "Aggregated")
lookback string optional Lookback to filter with (default: "1d")
geography string optional Region to filter with (default: "World")
dayOfWeek string optional Specific day of the week (default: "AllWeek" )

Available optional parameter values can be retrieved with the /universe route.

HTTP Request

GET /analytics/trades

Response fields

Example of JSON structure returned by the request:

{
  "instrument": "BTC-USDT.SPOT",
  "lookback": "1d",
  "size": "18000",
  "venue": "Aggregated",
  "geography": "World",
  "dayOfWeek": "AllWeek"
}

The response is a JSON object with the following fields:

Field Type Description
instrument string Name of the queried instrument
lookback string The specific lookback for this analytic
size string The average size of trades for the queried instrument and the venue/lookback pair
venue string The venue used to compute this analytic
geography string The trading hours that were used to filter the analytic
dayOfWeek string The day of the week used to filter the analytic

Get daily average volume

import requests

endpoint = '%s/analytics/volume?instrument=%s' % (base, instrument)
response = requests.get(endpoint, headers=headers)

This analytic gives the average daily volume of a pair on a venue based on specific lookbacks (one day, one week, one month) for a specific geography (trading hours) and a specific day in week.

This route takes the following query parameters:

Parameter Type Description
instrument string Instrument name (can be retrieved using the /instruments route)
venue string optional Venue name (default: "Aggregated")
lookback string optional Lookback to filter with (default: "1d")
geography string optional Region to filter with (default: "World")
dayOfWeek string optional Specific day of the week (default: "AllWeek" )

Available optional parameter values can be retrieved with the /universe route.

HTTP Request

GET /analytics/volume

Response fields

Example of JSON structure returned by the request:

{
  "instrument": "BTC-USDT.SPOT",
  "lookback": "1d",
  "volume": "90",
  "venue": "Aggregated",
  "geography": "World",
  "dayOfWeek": "AllWeek"
}

The response is a JSON object with the following fields:

Field Type Description
instrument string Name of the queried instrument
lookback string The specific lookback for this analytic
volume string The average daily volume for the queried instrument and the venue/lookback pair
venue string The venue used to compute this analytic
geography string The trading hours that were used to filter the analytic
dayOfWeek string The day of the week used to filter the analytic

Get money flow

import requests

endpoint = '%s/analytics/money-flow?instrument=%s' % (base, instrument)
response = requests.get(endpoint, headers=headers)

This analytic gives the ratio between buyers and sellers for a pair on a venue based on specific lookbacks (one day, one week, one month) for a specific geography (trading hours) and a specific day in week.

This route takes the following query parameters:

Parameter Type Description
instrument string Instrument name (can be retrieved using the /instruments route)
venue string optional Venue name (default: "Aggregated")
lookback string optional Lookback to filter with (default: "1d")
geography string optional Region to filter with (default: "World")
dayOfWeek string optional Specific day of the week (default: "AllWeek" )

Available optional parameter values can be retrieved with the /universe route.

HTTP Request

GET /analytics/money-flow

Response fields

Example of JSON structure returned by the request:

{
  "instrument": "BTC-USDT.SPOT",
  "lookback": "1d",
  "moneyFlow": "-0.03",
  "venue": "Aggregated",
  "geography": "World",
  "dayOfWeek": "AllWeek"
}

The response is a JSON object with the following fields:

Field Type Description
instrument string Name of the queried instrument
lookback string The specific lookback for this analytic
moneyFlow string The ratio between buyers, goes from -1 (market dominated by sellers) to 1 (market dominated by buyers)
venue string The venue used to compute this analytic
geography string The trading hours that were used to filter the analytic
dayOfWeek string The day of the week used to filter the analytic

The following analytics are estimations of how the market is behaving. They as based on statistical analysis and models. All estimations are provided with a confidence level of 95%.

Get annualized volatility

import requests

endpoint = '%s/analytics/volatility?instrument=%s' % (base, instrument)
response = requests.get(endpoint, headers=headers)

This analytic estimates annualized volatility of a pair using Aplo’s proprietary quantitative models. This route takes the following query parameters:

Parameter Type Description
instrument string Instrument name (can be retrieved using the /instruments route)
venue string optional Venue name (default: "Aggregated")
lookback string optional Lookback to filter with (default: "1d")
geography string optional Region to filter with (default: "World")
dayOfWeek string optional Specific day of the week (default: "AllWeek" )

Available optional parameter values can be retrieved with the /universe route.

HTTP Request

GET /analytics/volatility

Response fields

Example of JSON structure returned by the request:

{
  "instrument": "BTC-USDT.SPOT",
  "lookback": "1d",
  "volatility": "0.09",
  "venue": "Aggregated",
  "geography": "World",
  "dayOfWeek": "AllWeek"
}

The response is a JSON object with the following fields:

Field Type Description
instrument string Name of the queried instrument
lookback string The specific lookback for this analytic
volatility string The rate of volatility of the queried instrument, in the range [0, 1]
venue string The venue used to compute this analytic
geography string The trading hours that were used to filter the analytic
dayOfWeek string The day of the week used to filter the analytic

Get estimated seasonality

import requests

endpoint = '%s/analytics/seasonality?instrument=%s' % (base, instrument)
response = requests.get(endpoint, headers=headers)

This analytic estimates trade volume of a pair for specific lookahead (currently restricted to one day) using Aplo’s proprietary quantitative models. This route takes the following query parameters:

Parameter Type Description
instrument string Instrument name (can be retrieved using the /instruments route)
venue string optional Venue name (default: "Aggregated")
lookahead string optional Lookahead to filter with (default: "1d")

Available optional parameter values can be retrieved with the /universe route.

HTTP Request

GET /analytics/seasonality

Response fields

Example of JSON structure returned by the request:

{
  "instrument": "BTC-USDT.SPOT",
  "lookahead": "1d",
  "seasonality": "98",
  "venue": "Aggregated"
}

The response is a JSON object with the following fields:

Field Type Description
instrument string Name of the queried instrument
lookahead string The specific lookahead for this analytic
seasonality string The estimated trade volume for the queried instrument
venue string The venue used to compute this analytic

Get market impact

import requests

endpoint = '%s/analytics/marker-impact?instrument=%s&impact=%s&volume=%s' % (base, instrument, impact, volume)
response = requests.get(endpoint, headers=headers)

This route can represent three different analytic depending on the params used.
This route takes the following query parameters:

Parameter Type Description
instrument string Instrument name (can be retrieved using the /instruments route)
impact string optional Rate of market impact (in the range [0, 1])
volume string optional Notional volume
lookahead string optional Lookahead time

The lookahead parameter must have the following format:

Scale Value
h hour
d day
w week
m month
y year

Examples of valid lookahead values: 2d, 3.5w, 1m;

This route MUST take exactly 2 of the 3 optional parameters impact, volume and lookahead.

The returned analytic depends on the 2 parameters supplied:

HTTP Request

GET /analytics/market-impact

Response fields

Example of JSON structure returned by the request:

{
  "instrument": "BTC-USDT.SPOT",
  "lookahead": "1d",
  "volume": "67.23",
  "impact": "0.01",
  "venue": "Aggregated"
}

The response is a JSON object with the following fields:

Field Type Description
instrument string Name of the queried instrument
lookahead string The provided lookahead OR the estimated time required to trade the provided volume while staying below the provided impact
volume string The provided volume OR the estimated volume over the provided lookahead to be traded while staying below the provided market impact
impact string The provided market impact OR the estimated market impact over the provided lookahead if the provided volume are traded
venue string The venue used to compute this analytic

Virtual Accounts

The routes below relate directly to the virtual accounts themselves (creation/editing/list).
GET routes can take "virtualAccountId=XXX" as a query param, PATCH/PUT/POST routes can take "virtualAccountId" as a body param to indicate the specific virtual account to impact/use.
If no "virtualAccountId" (by default) is provided, the "Main Account" (indicated by a "virtualAccountId" of null) is used instead.

Create a virtual account

import requests

endpoint = '%s/accounts/%s/virtual-accounts/' % (base, accountId)
body = {
         "email": "usr1+test@aplo.io",
         "name": "Legitimate Businessperson",
       }
response = requests.post(endpoint, headers=headers, json=body)

This route allows you to create a virtual account.

HTTP Request

POST /accounts/:accountId/virtual-accounts/

Body Parameters

Parameter Type Description
name string Human readable name for this virtual account
email string optional Email address used to identify this virtual account

Response fields

Example of JSON structure returned by the request:

{
  "id": 9842,
  "accountId": "13b65571-3efc-53c0-acf2-d6761f5d39cf",
  "name": "Legitimate Businessperson",
  "email": "usr1+test@aplo.io",
  "earnRateTierId": null,
  "createdAt": "2022-03-01T11:24:10.015Z"
}

The returned body is a JSON object with the following properties:

Header Type Description
id number The virtual account Id
accountId string The virtual account's owner account Id
name string Name of the virtual account (can be null)
email string Email associated with the virtual account
earnRateTierId string Earn rate tier Id, used for the earn product (can be null to indicate the same rate tier as the parent account)
createdAt Date Date of account creation

Get all virtual accounts

import requests

endpoint = '%s/accounts/%s/virtual-accounts' % (base, accountId)
response = requests.get(endpoint, headers=headers)

This route returns all virtual accounts for the specified account. This route can take the following optional query parameters:

Parameter Type Description
email string Email filter for virtual accounts that contains the filter
name string Name filter for virtual accounts that contains the filter
id string Id filter for virtual accounts that contains the filter

HTTP Request

GET /accounts/:accountId/virtual-accounts

Response fields

Example of JSON structure returned by the request:

{
  "data": [
    {
      "id": 28545579,
      "accountId": "13b65571-3efc-53c0-acf2-d6761f5d39cf",
      "name": null,
      "email": "usr1+virtual@aplo.io",
      "earnRateTierId": null,
      "createdAt": "2022-03-01T11:24:10.015Z"
    },
    {
      "id": 1750416876,
      "accountId": "13b65571-3efc-53c0-acf2-d6761f5d39cf",
      "name": "Ursula Beohim",
      "email": "usr2+virtual@aplo.io",
      "earnRateTierId": null,
      "createdAt": "2022-03-01T12:24:10.015Z"
    }
  ],
  "count": 329
}

Where data is a JSON array of objects with the following properties:

Header Type Description
id number The virtual account Id
accountId string The virtual account's owner account Id
name string Name of the virtual account
email string Email associated with the virtual (can be null)account
earnRateTierId string Earn rate tier Id, used for the earn product (can be null to indicate the same rate tier as the parent account)
createdAt Date Date of account creation

Get specific virtual account's information

import requests

endpoint = '%s/accounts/%s/virtual-accounts/%s' % (base, accountId, virtualAccountId)
response = requests.get(endpoint, headers=headers)

This route allows users to retrieve the information of a specific virtual account.

HTTP Request

GET /accounts/:accountId/virtual-accounts/:virtualAccountId

Response fields

Example of JSON structure returned by the request:

{
  "id": 425221005,
  "accountId": "13b65571-3efc-53c0-acf2-d6761f5d39cf",
  "name": "Ursula Beohim",
  "email": "usr2+virtual@aplo.io",
  "earnRateTierId": null,
  "createdAt": "2022-03-01T12:24:10.015Z"
}

Where data is a JSON array of objects with the following properties:

Header Type Description
id number The virtual account Id
accountId string The virtual account's owner account Id
name string Name of the virtual account
email string Email associated with the virtual (can be null)account
earnRateTierId string Earn rate tier Id, used for the earn product (can be null to indicate the same rate tier as the parent account)
createdAt Date Date of account creation

Modify a virtual account

import requests

endpoint = '%s/accounts/%s/virtual-accounts/%s' % (base, accountId, virtualAccountId)
body = {
         "name": "Legitimate Businessdude",
       }
response = requests.patch(endpoint, headers=headers, json=body)

This route allows you to modify a virtual account.

HTTP Request

PATCH /accounts/:accountId/virtual-accounts/:virtualAccountId

Body Parameters

Parameter Type Description
name string optional Human readable name for this virtual account
email string optional Email address used to identify this virtual account

Response fields

Example of JSON structure returned by the request:

{
  "id": 9842,
  "accountId": "13b65571-3efc-53c0-acf2-d6761f5d39cf",
  "name": "Legitimate Businessdude",
  "email": "usr1+test@aplo.io",
  "earnRateTierId": null,
  "createdAt": "2022-03-01T11:24:10.015Z"
}

The returned body is a JSON object with the following properties:

Header Type Description
id number The virtual account Id
accountId string The virtual account's owner account Id
name string Name of the virtual account (can be null)
email string Email associated with the virtual account
earnRateTierId string Earn rate tier Id, used for the earn product (can be null to indicate the same rate tier as the parent account)
createdAt Date Date of account creation

Errors

The Aplo Trade API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your authentication is invalid.
403 Forbidden -- You do not have permission to access this endpoint. A missing User-Agent header may trigger it.
404 Not Found -- The specified ID could not be found.
405 Method Not Allowed -- You tried to access an endpoint with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
410 Gone -- This endpoint is no longer available.
429 Too Many Requests -- You're sending too many requests.
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.

Changelog

December 2025

November 2025

October 2025

August 2025

Banking overhaul:
Banking fees for both deposits and withdrawals have been added to Aplo's internal bank accounts.
You can now choose the bank account Aplo will use to send withdrawn funds.

May 2025

April 2025

For security reasons, the User-Agent header is now required for all incoming requests. Lack of User-Agent will trigger a 403 error.

February 2025

DEPRECATE the following routes:

Add a new route

The parameter -day in the GET /participants/:mpid/orders/:token(-:day) route has been renamed to :initialDay to reflect its actual value and has been made MANDATORY for this route, you now have to indicate both the :token and :initialDay when calling this route.

Add virtualAccountId optional parameters to all /participants routes in addition to the Virtual Account Trading section for clarity

Fix margin_ratio to margin_ratio_distance for Risk Response

November 2024

Billing rework:

October 2024

July 2024

March 2024

Authentication

The API authentication has been migrated from JSON Web Tokens(JWT) to API Keys.

February 2024

January 2024

December 2023

November 2023

Improve Fund Administration routes /user/trades, /user/orders and /user/activity and sister /export routes:

Add transferDuration and hasMemo to Universe Network route GET /networks

Improve external addresses (withdrawal addresses):

October 2023

September 2023

Improve all date/datetime query params and body params. They now support second/milliseconds/nanoseconds timestamps AND human readable strings

June 2023

April 2023

Handling of multi-day orders.

January 2023

Split of addresses into internal and external addresses. Similarly to banks, internal addresses are Aplo's addresses and are used for deposits. External addresses are your addresses that are used for withdrawals.

Additional external address information has been added in the related routes

December 2022

Addition of bank accounts for fiat deposit/withdrawal.

October 2022

Major overhaul to the assets and instrument naming convention meant to accomodate future/put/call classifications moving forward.

Trading

September 2022

Trading

Backoffice

August 2022

Summary of changes: removed most of the virtual accounts routes in favor of updating previous ones to support virtual accounts. Added documentation about withdrawal addresses, billing and earning APIs

Virtual Accounts

Deposit/Withdrawal Destinations

Deposit / Withdrawals / Withdrawal Requests / Transfer Requests

Withdrawal Addresses

Earning

Billing