NAV Navbar
javascript python

Web API

Overview

# Please note that many of the Python examples presented use type
# annotations introduced in Python 3.6. They are easy to remove
# manually if you are using an older version of Python. You could
# also use the strip-hints library to remove the type hints from
# the code. Examples have been tested with CPython 3.6+ only.

The information below should be used to help you consume our Web API.

URLs

OpenAPI

Public Endpoints

Public endpoints do not require authentication. This information is fundamental to the exchange and publicly available.

Time

GET /time

const axios = require('axios')

axios.get('https://api.zerohash.com/time')
import requests

requests.get('https://api.zerohash.com/time')

Sample Response

{
  "epoch": 1550174574
}

Return the current unix time of the server in seconds.

Authentication

const crypto = require('crypto')
const request = require('request-promise')

const makeRequest = (
  apiKey,
  apiSecret,
  passphrase,
  host,
  route,
  method,
  body
) => {
  // CREATE SIGNATURE
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + method + route + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  // Don't forget to base 64 encode your digest
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': apiKey,
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': passphrase
  }

  const derivedMethod = {
    POST: 'post',
    PUT: 'put',
    GET: 'get'
  }[method]

  const options = {
    headers,
    body,
    json: true
  }

  return request[derivedMethod](`https://${host}${route}`, options)
}
import hashlib
import hmac
import json
from base64 import b64decode, b64encode
from datetime import datetime
from typing import Any, Dict, Optional
from urllib.parse import urljoin

import requests
from logging import getLogger


# ℹ️ PLEASE NOTE: make sure you're pointing to the right environment:
# cert: https://api.cert.zerohash.com
# production: https://api.zerohash.com

BASE_URL = 'https://api.cert.zerohash.com'


# ℹ️ PLEASE NOTE: you should refer to the following article for instructions
# on how to create your API keys:
#
#   https://seedcx.zendesk.com/hc/en-us/articles/1500009663981-Creating-API-Keys
#
# ⚠️ WARNING: **THESE CREDENTIALS SHOULD NEVER BE STORED IN PLAINTEXT**
# API keys here are kept in plaintext for the purposes of demonstration.
# We highly encourage you to store your keys encrypted and only decrypt them
# when being used.
#
API_PUBLIC_KEY = '<please fill me in>'
API_PRIVATE_KEY = '<please fill me in>'
PASSPHRASE = '<please fill me in>'


def sign_request(api_private_key: str, method: str,
                 resource_path: str, json_body: str, timestamp: str) -> bytes:
    """Signs a HTTP payload to be sent to Zero Hash API.

    :param api_private_key: Key to sign the message with
    :param method: HTTP method
    :param resource_path: Relative path to the resource, e.g., /trades
    :param json_body: JSON as a string. Usually created via json.dumps(dict)
    :param timestamp: Unix Epoch time as a string
    :return: Base64 encoded digest
    """

    # ℹ️ PLEASE NOTE: the timestamp, HTTP method, resource path and JSON
    # body used to generate the signature here must be signed exactly as send
    # to the underlying HTTP request
    msg = bytes(
        timestamp + method + resource_path + json_body,
        encoding='utf-8'
    )
    hm = hmac.new(
        key=b64decode(api_private_key),
        msg=msg,
        digestmod=hashlib.sha256
    )
    return b64encode(hm.digest()).decode()


def build_headers() -> Dict[str, Any]:
    """Builds a template with the HTTP headers to be send in requests
    to Zero Hash API.
    """

    # ℹ️ PLEASE NOTE: datetime.timestamp is available only in Python 3.3+
    # This is the Unix epoch.
    timestamp = str(int(datetime.now().timestamp()))

    return {
        'X-SCX-API-KEY': API_PUBLIC_KEY,
        'X-SCX-SIGNED': '<to be filled>', # PLEASE NOTE: will be auto filled below
        'X-SCX-TIMESTAMP': timestamp,
        'X-SCX-PASSPHRASE': PASSPHRASE
    }


def send_signed_http_request(
    method: str, resource_path: str, body: Optional[Dict[str, str]] = None
) -> requests.Response:
    """Builds and sends an HTTP request with a signature to the Zero Hash API.

    :param method: HTTP method, such as GET, POST, PUT, PATCH, DELETE
    :param resource_path: Relative path to the resource, e.g., /trades
    :param body: Dictionary for serializing into the JSON body of the request.
                 For GET requests, this can be omitted or set to an empty dict.
                 Nothing will be sent, but it is required for the signature.
    :return: requests.Response object
    """
    if body is None:
        body = {}

    headers = build_headers()

    json_body = json.dumps(body, separators=(',', ':'))
    signature = sign_request(
        API_PRIVATE_KEY,
        method,
        resource_path,
        json_body,
        headers['X-SCX-TIMESTAMP']
    )
    headers['X-SCX-SIGNED'] = signature

    absolute_url = urljoin(BASE_URL, resource_path)

    # ⚠️ WARNING: We are printing your signature headers to make it easier for
    # troubleshooting in your local testing environment. For security reasons,
    # please never do this on any real staging / production servers.
    print('\n### REQUEST [{0}]\n'.format(absolute_url))
    print('{0} {1}\n{2}'.format(method, resource_path, body))
    print('X-SCX-API-KEY: {0}'.format(headers['X-SCX-API-KEY']))
    print('X-SCX-TIMESTAMP: {0}'.format(headers['X-SCX-TIMESTAMP']))
    print('X-SCX-PASSPHRASE: {0}'.format(headers['X-SCX-PASSPHRASE']))
    print('X-SCX-SIGNED: {0}'.format(headers['X-SCX-SIGNED']))

    request_args = {
        'method': method,
        'url': absolute_url,
        'headers': headers
    }
    if body:
        request_args['data'] = json_body
        headers['Content-Type'] = 'application/json'

    response = requests.request(**request_args)

    # ℹ️ PLEASE NOTE: for production code you might want to consider a proper
    # logging solution.
    print('\n===> RESPONSE ###\n')
    print(response.status_code)
    print(response.text)

    return response


if __name__ == '__main__':
    # ⚠️ WARNING: We are printing your API keys here to make it easier for
    # troubleshooting in your local testing environment. For security reasons,
    # please never do this on any real staging / production servers.
    print('\n### API KEYS ###\n')
    print('API public key: {0}'.format(API_PUBLIC_KEY))
    print('API private key: {0}'.format(API_PRIVATE_KEY))
    print('Passphrase: {0}'.format(PASSPHRASE))

    send_signed_http_request('GET', '/index?underlying=BTC&quoted_currency=USD')
    send_signed_http_request('GET', '/trades')
    send_signed_http_request('GET', '/participants')

Example Headers

{
  "X-SCX-API-KEY": "h2yFu1uijCDEqkbdop4GAF",
  "X-SCX-SIGNED": "PFMlg+bMFVjjAiGPLR/zJCStmiiOIeyz5NIOZEmpfH0=",
  "X-SCX-TIMESTAMP": 1550175822,
  "X-SCX-PASSPHRASE": "passphrase"
}

Zero Hash Uses HMAC SHA-256 verification to ensure the authenticity of every API request.

To Authenticate with us, you will need to set the following headers:

Header Description
X-SCX-API-KEY Your public key
X-SCX-SIGNED Signature for your request
X-SCX-TIMESTAMP Unix timestamp
X-SCX-PASSPHRASE Your passphrase

To sign your request:

  1. Concatenate timestamp + method + route + request body

Example: 1549468233POST/orders{"client_order_id":"abcdefg","instrument_code":"COSP:BTC/USD","market_code":"SCXM","order_type":"limit","price":"3780","quantity":"10","side":"buy"}

  1. Generate an HMAC digest using your private key (using HMAC SHA-256).

Example: Private Key = 2mC4ZvVd4goRkuJm+rjr9byUiaUW1b6tVN4xy9QXNSE=

  1. Encode the HMAC digest in Base64.

Using the above private key should produce a base64 encoded digest of: +p94Yo3z33zvTmoA+BFtzQIW+qJz1X8IZcnuudpX6A8=

Private Endpoints

# The below Python examples make use of the functions defined above.

Index

GET /index

Sample Response

{
  "timestamp": 1564686909724,
  "index": "BTC/USD",
  "underlying": "BTC",
  "quoted_currency": "USD",
  "value": 1234.5678901234
}

Query for the most recently calculated Zero Hash Index value.

The following query parameters are required:

Parameter Description Type
timestamp When the index was calculated timestamp
index The specific index, which is the unique combination of underlying and quoted_currency string
underlying The asset being valued string
quoted_currency The asset in which the underlying is being valued string
value The index price for the underlying asset, as quoted in the quoted_currency number

Assets

GET /assets

Sample Response

{
  "message": [
    {
      "symbol": "SOL",
      "name": "Solana",
      "chain_code": "solana",
      "type": "crypto",
      "model": "account_based",
      "withdrawal_minimum": "0.000001",
      "stablecoin": false,
      "precision": 9,
      "tag_name": "none",
      "fee_asset": "",
      "rfq_liquidity_enabled": true,
      "custody_enabled": true,
      "deposit_address_creation": "none",
      "deposits_onchain_confirms": 0,
      "ny_allowed": false
    },
    {
      "symbol": "USD",
      "name": "US Dollar",
      "chain_code": "",
      "type": "fiat",
      "model": "none",
      "withdrawal_minimum": "0.01",
      "stablecoin": false,
      "precision": 2,
      "tag_name": "none",
      "fee_asset": "",
      "rfq_liquidity_enabled": true,
      "custody_enabled": true,
      "deposit_address_creation": "none",
      "deposits_on_chain_confirms": 0,
      "ny_allowed": false
    }
  ]
}

Query for all the assets supported by Zero Hash.

Optional query parameters include:

Parameter Description Type
stablecoin Denotes whether the asset is considered a stablecoin boolean
chain_code Identifies the protocol the asset is listed on string
symbol Asset code used throughout the system string
ny_allowed Shows if transactions for an asset are allowed in New York boolean

Trades

GET /trades

Sample Response

{
  "message":[
    {...}, // see trade by ID response below
    {...}  // see trade by ID response below
  ],
  "page":1,
  "total_pages":32
}

This returns an array of all trades received by Zero Hash where the requestor is the Platform, either party associated with the trade, or the account group where the trade was settled.

Optional query parameters include:

GET /trades/:trade_id

A particular trade that has been submitted to Zero Hash for settlement. Note: the trade_id field is the Zero Hash-provided identifier returned as a response to the trade submission endpoints.

Sample Response

{
  "message": {
    "trade_id": "9411a2d9-8964-47d0-8971-a52db2f65748",
    "client_trade_id": "fjfd9wekdwoc0sdkcs09w",
    "session_id": "20190801000000",
    "trade_state": "terminated",
    "market_identifier_code": "SCXM",
    "reporting_party": "00SCXM",
    "settlement_schedule": "ABCDEF",
    "symbol": "BTC/USD",
    "trade_quantity": "4",
    "trade_price": "10000",
    "trade_type": "block",
    "physical_delivery": true,
    "comment": null,
    "last_update": 1565832456717,
    "transaction_timestamp": 1565731066447,
    "settlement_timestamp": 1565731965906,
    "accepted_timestamp": 1565731066768,
    "defaulted_timestamp": null,
    "settled_timestamp": 1565794980952,
    "contract_size": 1,
    "bank_fee": "1.00",
    "underlying": "BTC",
    "quoted_currency": "USD",
    "trade_reporter": "user@00SCXM.com",
    "platform_code": "00SCXM",
    "product_type": "spot",
    "parties_anonymous": false,
    "parties": [
      {
        "participant_code": "0M2CKW",
        "side": "buy",
        "asset": "BTC",
        "amount": "4",
        "liquidity_indicator": null,
        "execution_id": "ex_id1",
        "order_id": "foo",
        "desk_code": null,
        "trading_account_code": null,
        "obligations_outstanding_timestamp": null,
        "current_obligations_met_timestamp": null,
        "settlement_state": "settled",
        "client_order_id": null,
        "settling": true,
        "account_label": "general",
        "commission": null,
        "commission_asset": null,
        "commission_payor_participant_code": null,
        "commission_payor_account_group": null,
        "commission_payor_account_label": null
      },
      {
        "participant_code": "1J32WQ",
        "side": "sell",
        "asset": "USD",
        "amount": "40000",
        "liquidity_indicator": null,
        "execution_id": "ex_id2",
        "order_id": "foo",
        "desk_code": null,
        "trading_account_code": null,
        "obligations_outstanding_timestamp": null,
        "current_obligations_met_timestamp": null,
        "settlement_state": "settled",
        "client_order_id": null,
        "settling": true,
        "account_label": "general",
        "commission": null,
        "commission_asset": null,
        "commission_payor_participant_code": null,
        "commission_payor_account_group": null,
        "commission_payor_account_label": null
      }
    ],
    "network_fee_notional": null,
    "network_fee_quantity": null,
    "total_notional": "0.02",
    "asset_cost_notional": "0.02"
  }
}

POST /trades

Sample Request

const postTrades = () => {
  const body = {
    symbol: "BTC/USD",
    trade_reporter: "reporter@mail.com",
    reporting_party: "AAAAAA",
    settlement_schedule: "ABCDEF",
    client_trade_id: "5155f7c9-95cb-4556-ab89-c178943a7111",
    trade_price: "1",
    trade_quantity: "0.0001",
    platform_code: "AAAAAA",
    parties_anonymous: false,
    transaction_timestamp: 1670958435349,
    product_type: "spot",
    trade_type: "regular",
    physical_delivery: true,
    parties: [
      {
        participant_code: "BBBBBB",
        asset: "BTC",
        side: "buy",
        settling: true
      },
      {
        participant_code: "CCCCCC",
        asset: "USD",
        side: "sell",
        settling: true
      }
    ]
  }

  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/trades' + JSON.stringify(
    body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    'https://api.zerohash.com/trades',
    options
  )
}

Sample Response

{
  "message": {
    "trade_id": "92616fce-31d3-465a-af01-0fb5d2dc4d40",
    "client_trade_id": "f2f14251-e296-42ac-9bc7-01c9186b9219",
    "session_id": "20190801000000",
    "trade_state": "terminated",
    "market_identifier_code": "TEST",
    "trade_reporter": "reporter@mail.com",
    "reporting_party": "SGC7CQ",
    "settlement_schedule": "ABCDEF",
    "symbol": "BTC/USD",
    "trade_quantity": "1.0",
    "trade_price": "10000.000000",
    "trade_type": "regular",
    "physical_delivery": true,
    "comment": "Some comments about the trade for Zero Hash to store",
    "settlement_timestamp": 1575849302321,
    "transaction_timestamp": 1575849302321,
    "accepted_timestamp": 1564686909724,
    "settled_timestamp": null,
    "defaulted_timestamp": null,
    "contract_size": 1,
    "bank_fee": "1.00",
    "underlying": "BTC",
    "quoted_currency": "USD",
    "platform_code": "00TEST",
    "product_type": "spot",
    "parties_anonymous": true,
    "last_update": 1564686909724,
    "parties": [
      {
        "participant_code": "PKOHXY",
        "side": "buy",
        "asset": "BTC",
        "amount": "1.0",
        "liquidity_indicator": null,
        "execution_id": null,
        "order_id": null,
        "current_obligations_met_timestamp": 1564686909724,
        "obligations_outstanding_timestamp": 1564686909724,
        "client_order_id": null,
        "settling": true
      },
      {
        "participant_code": "S1I5ED",
        "side": "sell",
        "asset": "USD",
        "amount": "4000.0000",
        "liquidity_indicator": null,
        "execution_id": null,
        "order_id": null,
        "current_obligations_met_timestamp": 1564686909724,
        "obligations_outstanding_timestamp": 1564686909724,
        "client_order_id": null,
        "settling": true
      }
    ]
  }
}

Allows a Trade Reporter to post executed spot trades to Zero Hash for settlement. The following fields are part of the submission.

Parameter Description Type
client_trade_id A unique identifier for the trade, generally produced by the Platform on which the trade was executed
Note: this must be unique, per platform, per 72 hour period
string
trade_reporter A text field to indicate the name or identifier of the person or entity submitting the trade, e.g. an email address string
reporting_party (optional) The original reporter of the trade. This field is optional and must be a 6 digit participant code of which you have proper relationships with string
settlement_schedule (optional) Instructs Zero Hash to settle trades according to a certain schedule string
platform_code The unique identifier to the Platform on which the trade was executed, as provided by Zero Hash string
market_identifier_code (optional) The ISO 10383 market identifier code for the platform string
symbol A free text field to identify the pair being traded, e.g. BTC/USD string
product_type spot or forward string
trade_type The type of trade to be settled
Valid values are regular or block
string
trade_price The price the trade was executed, refer to
Note: if the amount is included per side, then this must equal to the seller's amount divided by the buyer's amount accurate for up to 20 figures
string
trade_quantity (conditional) The quantity purchased
Note: if the amount is included per side, then this should not be included, otherwise it is required
string
physical_delivery A boolean statement to indicate if the trade is physically delivered
Currently Zero Hash only supports physically-settled trades, i.e. a value of true
boolean
transaction_timestamp The unix timestamp the trade was executed on the external platform in milliseconds timestamp
comment (optional) An optional field to use if there is any additional information needed string
parties_anonymous A boolean flag to determine if the counterparties are known to each other
Must be false if the platform_code is also a counterparty to the trade
boolean
parties[] The counterparties of the trade
Currently Zero Hash only supports 2 parties per trade
array
settlement_price_index_id (conditional) The unique identifier of the benchmark settlement price to be used when calculating settlement obligations on trades that are settled at Zero Hash - required for forwards only string
settlement_timestamp (optional) The datetime when final settlement will first be attempted - if not included, the standard platform settlement instructions will be applied number (unix ms timestamp)
expiry_timestamp (optional) The last datetime that the product can be traded, and the datetime that all final prices will be set, i.e. the fixing date - relevant for forwards only
Note: after this point, there is no more ability to exit the trade or change its economics
number (unix ms timestamp)
bank_fee (optional) An optional field that clients can use to specify the fee taken by the banking partner. This is used for reporting purposes only (supports 2 decimal places) string
network_fee_notional (optional) The notional value of the network fee applied to the trade if applicable string
network_fee_quantity (optional) The quantity of the network fee applied to the trade string
total_notional (optional) The notional cost amount plus network fee notional amount string
asset_cost_notional (optional) The cost of the asset in the notional amount string

Parameters for a specific party to a trade.

Parameter Description Type
side The side of the party, buy or sell string
participant_code The participant code as assigned by Zero Hash
Note: this will be Anonymous for counterparties to the trade if the parties_anonymous boolean was flagged as true by the Trade Reporter
string
asset The asset that is being received by the party string
amount (conditional) The amount of the asset that the party is receiving
Note: if the trade_quantity is included, then this should not be included, otherwise it is required
string
liquidity_indicator (optional) This an optional field that can be sent to mark whether the party added or removed liquidity upon execution, used for reporting purposes only string
client_order_id (optional) This is an optional field that may have been sent by your clients and can be sent as part of the request, used for reporting purposes only string
order_id (optional) This is an optional field that can be used to identify orders within your system, used for reporting purposes only string
execution_id (optional) This an optional field that can be used to identify the ID of the execution for orders, used for reporting purposes only string
settling This field states which side(s) will be settled string
account_label (optional) The account label allocated to the trade string
commission (optional) Amount of the commission collected for the trade string
commission_asset (optional) The asset type (e.g. USD, BTC) for the collected commission string
commission_payor_participant_code (optional) The participant code tied to the commission string
commission_payor_account_group (optional) The account group tied to the commission string
commission_payor_account_label (optional) The account label tied to the commission string

As a response, all information provided in the trade submission will be returned, plus the following additional fields:

Parameter Description Type
trade_id A unique ID from Zero Hash string
trade_state accepted, active, terminated string
accepted_timestamp The timestamp when the trade was first accepted into Zero Hash with a trade_state of accepted timestamp
current_obligations_met_timestamp The most recent timestamp when the trade reached the settlement_state of current_obligations_met. Will be null if this has not occured yet timestamp
obligations_outstanding_timestamp The most recent timestamp when the trade reached the settlement_state of obligations_outstanding. Will be null if this has not occured yet timestamp
settlement_state null, obligations_oustanding, current_obligations_met, counterparty_defaulted, settled or defaulted string
settled_timestamp The timestamp when the trade fully settled all obligations, thereby reaching the terminal settlement_state of settled. Will be null if this has not occured yet timestamp
defaulted_timestamp The timestamp when the trade defaulted due to obligations not being met on time, thereby reaching the terminal settlement_state of defaulted. Will be null if this has not occured yet timestamp
last_update The timestamp that indicates the last time the trade was updated timestamp
session_id This field reflects the Session Period - A discrete period in time encompassing all trading for a platform. This could be as short as one minute or as long as one business day. string

Trade Price

A trade_price with any precision is accepted, however note that final settlement amounts are limited to the asset’s currency precision limit. Further, when calculating trade notional and settlement values, Zero Hash utilizes banker's rounding. See Precision column for more details.

Quantity and Amount

There are 2 methods of submitting trade price, quantity and amount information to Zero Hash. Depending on your setup, one may be more appropriate than the other:

  1. Submit trade_price and trade_quantity and we will therefore calculate the amount that each side will receive, e.g. for a BTC/USD trade, you may submit a trade_price of 10,000 and a trade_quantity of 1. We would therefore calculate that the buyer receives 1 BTC and the seller receives $10,000. This model is useful for trading platforms that have more defined instruments.
  2. Submit trade_price and the amount field per side, which means you explicitly state the amount that each side receives, e.g. for a BTC/USD trade, you may submit a trade_price of 10,000 and an amount of 1 for the buy side an amount of 10000 for the sell side. This is useful for platforms that have lots of flexibility in the amounts and assets that are traded. Note: if the amount is included per side, then the trade_price must equal to the seller's amount divided by the buyer's amount, accurate for up to 20 figures.

Physical Delivery

This boolean determines if a product is physically or financially-settled.

Parties Anonymous

The parties_anonymous field is used to protect counterparty information. In the event that a Trade Reporter wishes to keep the counterparty details anonymous, this flag can be set to true. This is relevant for brokers and other types of agency execution providers.

Trade State

Settlement State

POST /trades/batch

Sample Request

[
  {
    "symbol": "BTC/USD",
    "trade_reporter": "reporter@mail.com",
    "reporting_party": "AAAAAA",
    "settlement_schedule": "ABCDEF",
    "client_trade_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
    "trade_price": "1",
    "trade_quantity": "0.0001",
    "platform_code": "AAAAAA",
    "parties_anonymous": false,
    "transaction_timestamp": 1602182786660,
    "product_type": "spot",
    "trade_type": "regular",
    "physical_delivery": true,
    "parties": [
      {
        "participant_code": "BBBBBB",
        "asset": "BTC",
        "side": "buy",
        "settling": true
      },
      {
        "participant_code": "CCCCCC",
        "asset": "USD",
        "side": "sell",
        "settling": true
      }
    ]
  },
  {
    "symbol": "BTC/USD",
    "trade_reporter": "reporter@mail.com",
    "reporting_party": "DDDDDD",
    "settlement_schedule": "ABCXYZ",
    "client_trade_id": "5155f7c9-95cb-4556-ab89-c178943a7222",
    "trade_price": "2",
    "trade_quantity": "0.0002",
    "platform_code": "DDDDDD",
    "parties_anonymous": false,
    "transaction_timestamp": 1602182786660,
    "product_type": "spot",
    "trade_type": "regular",
    "physical_delivery": true,
    "parties": [
      {
        "participant_code": "EEEEEE",
        "asset": "BTC",
        "side": "buy",
        "settling": true
      },
      {
        "participant_code": "FFFFFF",
        "asset": "USD",
        "side": "sell",
        "settling": true
      }
    ]
  }
]

Sample Response

{
  "message": [
    {
      "trade_id": "a51d841b-0b1f-441c-96e3-fd164e0b3ff8",
      "client_trade_id": "5155f7c9-95cb-4556-ab89-c178943a7111",
      "session_id": "20190801000000",
      "trade_state": "accepted",
      "market_identifier_code": null,
      "trade_reporter": "reporter@mail.com",
      "reporting_party": "AAAAAA",
      "settlement_schedule": "ABCDEF",
      "symbol": "BTC/USD",
      "trade_quantity": "0.0001",
      "trade_price": "1",
      "trade_type": "regular",
      "physical_delivery": true,
      "comment": null,
      "last_update": 1602526124763,
      "transaction_timestamp": 1602182786660,
      "accepted_timestamp": 1602526124692,
      "defaulted_timestamp": null,
      "settled_timestamp": null,
      "expiry_timestamp": null,
      "settlement_timestamp": null,
      "settlement_price_index_id": null,
      "contract_size": 1,
      "bank_fee": "1.00",
      "underlying": "BTC",
      "quoted_currency": "USD",
      "trade_reporter": "AAAAAA",
      "platform_code": "AAAAAA",
      "product_type": "spot",
      "parties_anonymous": false,
      "parties": [
        {
          "participant_code": "BBBBBB",
          "side": "buy",
          "asset": "BTC",
          "amount": "null",
          "liquidity_indicator": null,
          "execution_id": null,
          "order_id": null,
          "obligations_outstanding_timestamp": null,
          "current_obligations_met_timestamp": null,
          "settlement_state": null,
          "client_order_id": null,
          "collateral_percentage": null
        },
        {
          "participant_code": "CCCCCC",
          "side": "sell",
          "asset": "USD",
          "amount": "null",
          "liquidity_indicator": null,
          "execution_id": null,
          "order_id": null,
          "obligations_outstanding_timestamp": null,
          "current_obligations_met_timestamp": null,
          "settlement_state": null,
          "client_order_id": null,
          "collateral_percentage": null
        }
      ],
      "platform_name": null
    },
    {
      "trade_id": "fe47ef4b-43d3-41c6-a7e9-42e414a6b34e",
      "client_trade_id": "5155f7c9-95cb-4556-ab89-c178943a7222",
      "session_id": "20190801000000",
      "trade_state": "accepted",
      "market_identifier_code": null,
      "trade_reporter": "reporter@mail.com",
      "reporting_party": "DDDDDD",
      "settlement_schedule": "ABCXYZ",
      "symbol": "BTC/USD",
      "trade_quantity": "0.0002",
      "trade_price": "2",
      "trade_type": "regular",
      "physical_delivery": true,
      "comment": null,
      "last_update": 1602526124648,
      "transaction_timestamp": 1602182786660,
      "accepted_timestamp": 1602526124637,
      "defaulted_timestamp": null,
      "settled_timestamp": null,
      "expiry_timestamp": null,
      "settlement_timestamp": null,
      "settlement_price_index_id": null,
      "contract_size": 1,
      "bank_fee": "1.00",
      "underlying": "BTC",
      "quoted_currency": "USD",
      "trade_reporter": "DDDDDD",
      "platform_code": "DDDDDD",
      "product_type": "spot",
      "parties_anonymous": false,
      "parties": [
        {
          "participant_code": "EEEEEE",
          "side": "buy",
          "asset": "BTC",
          "amount": "null",
          "liquidity_indicator": null,
          "execution_id": null,
          "order_id": null,
          "obligations_outstanding_timestamp": null,
          "current_obligations_met_timestamp": null,
          "settlement_state": null,
          "client_order_id": null,
          "collateral_percentage": null
        },
        {
          "participant_code": "FFFFFF",
          "side": "sell",
          "asset": "USD",
          "amount": "null",
          "liquidity_indicator": null,
          "execution_id": null,
          "order_id": null,
          "obligations_outstanding_timestamp": null,
          "current_obligations_met_timestamp": null,
          "settlement_state": null,
          "client_order_id": null,
          "collateral_percentage": null
        }
      ],
      "platform_name": null
    }
  ]
}

Allows a Trade Reporter to post multiple trades to Zero Hash for settlement. All trades submitted together must each independently pass validation for the batch to be accepted. If any trade is rejected, the entire batch will be rejected. This is useful for liquidity providers that wish to capture a spread between two counterparty trades.

The field requirements are the same as POST /trades, so please refer to the section above.

Positions

GET /positions

const getPositions = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/positions' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }
  return request.get(`https://api.zerohash.com/positions`, options)
}
accounts = make_seed_request('GET', '/positions', {})

Sample Response

{
  "message": [
    {
      "platform_code": "PLAT01",
      "participant_code": "CUST01",
      "asset": "BTC",
      "position_all_open_trades": "10.02",
      "position_all_accepted_trades_only": "10.02",
      "position_all_active_trades_only": "0"
    },
    {
      "platform_code": "PLAT01",
      "participant_code": "CUST01",
      "asset": "USD",
      "position_all_open_trades": "-100200",
      "position_all_accepted_trades_only": "-100200",
      "position_all_active_trades_only": "0"
    },
    {
      "platform_code": "PLAT02",
      "participant_code": "CUST01",
      "asset": "USDC",
      "position_all_open_trades": "-110000",
      "position_all_accepted_trades_only": "0",
      "position_all_active_trades_only": "-110000"
    },
    {
      "platform_code": "PLAT02",
      "participant_code": "CUST01",
      "asset": "USD",
      "position_all_open_trades": "109670",
      "position_accepted_trades_only": "0",
      "position_active_trades_only": "109670"
    }
  ]
}

Returns an array of all positions maintained at Zero Hash for the participant issuing the query. The response will include positions for all platforms for which the participant is active. Response parameters listed below.

Query parameters include:

Response:

Parameter Description Type
platform_code The code of the platform for the position string
participant_code The code of the participant that holds the position string
asset The asset code for the for the position, e.g. USD string
position_all_open_trades The net position of all open trades in the asset, i.e. trades with a trade_state of accepted or active string
position_accepted_trades_only The net position of all trades in the asset with a trade_state of accepted, i.e. trades where settlement has not yet been attempted string
position_active_trades_only The net position of all trades in the asset with a trade_state of active, i.e. trades where settlement has been attempted but was unsuccessful string

GET /positions/platform/:platform_code

const getPositionsForPlatform = (platformCode: string) => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/positions/' + platformCode + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/positions/platform/' + platformCode,
    options
  )
}
accounts = make_seed_request('GET', '/positions/platform/PLAT01', {})

Sample Response

{
  "message": [
    {
      "platform_code": "PLAT01",
      "participant_code": "CUST01",
      "asset": "BTC",
      "position_all_open_trades": "10.02",
      "position_all_accepted_trades_only": "10.02",
      "position_all_active_trades_only": "0"
    },
    {
      "platform_code": "PLAT01",
      "participant_code": "CUST01",
      "asset": "USD",
      "position_all_open_trades": "-100200",
      "position_all_accepted_trades_only": "-100200",
      "position_all_active_trades_only": "0"
    },
    {
      "platform_code": "PLAT01",
      "participant_code": "CUST02",
      "asset": "USDC",
      "position_all_open_trades": "-110000",
      "position_all_accepted_trades_only": "0",
      "position_all_active_trades_only": "-110000"
    },
    {
      "platform_code": "PLAT01",
      "participant_code": "CUST02",
      "asset": "USD",
      "position_all_open_trades": "109670",
      "position_accepted_trades_only": "0",
      "position_active_trades_only": "109670"
    }
  ]
}

Returns an array of all positions maintained at Zero Hash for the platform issuing the query. The response will include positions for all participants active on the platform. Response parameters listed below.

Query parameters include:

Response:

Parameter Description Type
platform_code The code of the platform for the position string
participant_code The code of the participant that holds the position string
asset The asset code for the for the position, e.g. USD string
position_all_open_trades The net position of all open trades in the asset, i.e. trades with a trade_state of accepted or active string
position_accepted_trades_only The net position of all trades in the asset with a trade_state of accepted, i.e. trades where settlement has not yet been attempted string
position_active_trades_only The net position of all trades in the asset with a trade_state of active, i.e. trades where settlement has been attempted but was unsuccessful string

Accounts

GET /accounts

const getAccounts = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/accounts' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(`https://api.zerohash.com/accounts`, options)
}
accounts = make_seed_request('GET', '/accounts', {})

Sample Response

{
  "message": [
    {
      "asset": "USD",
      "account_owner": "ABCDEF",
      "account_type": "collateral_deficiency",
      "account_group": "XYZ456",
      "account_label": "general",
      "balance": "0.00",
      "account_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
      "last_update": 1554395972174
    }
  ],
  "page": 1,
  "total_pages": 1
}

Query parameters include:

Returns an array of all accounts with a non-zero balance maintained at Zero Hash and their balances as of the most recent settlement run. Response parameters listed below.

Parameter Description Type
asset The asset code for the specific account, e.g. USD string
account_owner The code of the participant that owns the account string
account_type available, collateral, payable, receivable or collateral_deficiency string
account_group The group that the account is a part of string
account_label The account label associated with the account string
balance The balance in the account string
account_id Unique ID of the specific account string
last_update Timestamp when the account balance was updated timestamp

Assets

Refer to our FAQ page to see which assets we support and their corresponding asset codes.

Account Type

Account types refer to their utilization. Zero Hash maintains 5 account types:

Refer to our FAQ for more information: What types of accounts are supported?

Account Group

Account groups are utilized as part of the Zero Hash settlement infrastructure, to determine for which purpose the funds in the account have been allocated. Generally, an account group refers to a platform.

Refer to our FAQ for more information: What is an account group?

Account Label

Account Labels can be thought of as “sub account groups”. Within each account group, you can have many Account Labels. They are used to separate funds at a more granular level. The default value is general.

Refer to our FAQ for more information: What is an Account Label?

GET /accounts/net_delivery_obligations

const getNDO = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/accounts/net_delivery_obligations' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    `https://api.zerohash.com/accounts/net_delivery_obligations`,
    options
  )
}
account = make_seed_request('GET', '/accounts/net_delivery_obligations', {})

Sample Response

{
  "message": [
    {
      "asset": "USD",
      "amount": "10532.15",
      "account_group": "00SCXM",
      "account_label": "general"
    },
    {
      "asset": "BTC",
      "amount": "3",
      "account_group": "00SCXM",
      "account_label": "general"
    }
  ]
}

Your current net delivery obligations (NDO) across all accounts. See here for more information on NDOs: What does NDO mean?

Response parameters listed below.

Parameter Description Type
asset The asset code for the specific account, e.g. USD string
amount The amount owed string
account_group The sub account determination used for allocating towards settlements string
account_label The account label associated with the account string

GET /accounts/:account_id

const getAccount = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/accounts/e5e18303-a352-4c28-8dab-3779e66a659b' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    `https://api.zerohash.com/accounts/e5e18303-a352-4c28-8dab-3779e66a659b`,
    options
  )
}
account = make_seed_request('GET', '/accounts/e5e18303-a352-4c28-8dab-3779e66a659b', {})

Sample Response

{
  "message": {
    "asset": "USD",
    "account_owner": "ABC123",
    "account_type": "collateral_deficiency",
    "account_group": "00SCXM",
    "account_label": "general",
    "balance": "0.00",
    "account_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
    "last_update": 1554395972174
  }
}

Information about a specific account. Response parameters listed below.

Parameter Description Type
asset The asset code for the specific account, e.g. USD string
account_owner The code of the participant that owns the account string
account_type available, collateral, payable, receivable or collateral_deficiency string
account_group The sub account determination used for allocating towards settlements string
balance The balance in the account string
account_id Unique ID of the specific account string
last_update Timestamp of last settlement run timestamp
account_label The account label associated with the account string

GET /accounts/:account_id/run_history

Sample Request

const getAccountRunHistory = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/accounts/e5e18303-a352-4c28-8dab-3779e66a659b/run_history' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    `https://api.zerohash.com/accounts/e5e18303-a352-4c28-8dab-3779e66a659b/run_history`,
    options
  )
}

Sample Response

{
  "message": [
    {
      "run_timestamp": 1549577062214,
      "run_type": "settlement",
      "run_id": "500",
      "change": "2000",
      "new_balance": "146645"
    },
    {
      "run_timestamp": 1520134020000,
      "run_type": "deposit",
      "run_id": "480",
      "change": "100000",
      "new_balance": "144645"
    },
    {
      "run_timestamp": 1510101010000,
      "run_type": "withdrawal",
      "run_id": "375",
      "change": "-20000",
      "new_balance": "44645"
    }
  ],
  "page": 1,
  "total_pages": 32
}

Returns the history of grouped settlements, deposits, withdrawals and other changes that have been applied to an account to lead up to its current balance.

Parameter Description Type
run_timestamp The time that the particular run was executed timestamp
run_type The type of run string
run_id A unique ID for the particular run string
change The net change to the account due to all movements within the particular run string
new_balance The new account balance post-run string

Run Type

A run is a group of movements that pertain to the same type of change to an account. They are split into the following buckets:

Run Description
deposit deposit represents a new deposit into the particular account, always increasing the total balance of the account
execution_fee execution_fee represents a run to process fees incurred from trading on a Zero Hash liquidity venue
network_fee network_fee represents any and all blockchain network fees applied to an account, always decreasing the total balance of the account
settlement settlement is a group of movements due to margining and settling trades, which may increase or decrease the account balance
transfer transfer represents an internal transfer to or from an account at Zero Hash
withdrawal withdrawal represents an approved and processed withdrawal from a particular account, always decreasing the total balance of the account

GET /accounts/:account_id/movements

Sample Request

const getAccountMovements = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/accounts/e5e18303-a352-4c28-8dab-3779e66a659b/movements' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    `https://api.zerohash.com/accounts/e5e18303-a352-4c28-8dab-3779e66a659b/movements`,
    options
  )
}

Sample Response

{
  "message": [
    {
      "run_id": "500",
      "movement_timestamp": 1554395972174,
      "movement_id": "ab938734-0aa6-4378-baa1-2cc56aeee757",
      "movement_type": "final_settlement",
      "trade_id": "951806f4-d3ba-42c4-96fe-8083cd3202cf",
      "deposit_reference_id": null,
      "withdrawal_request_id": null,
      "change": "100",
      "parent_link_id": "f99411c3-5958-42f0-9ab7-d94d14221786"
    },
    {
      "run_id": "500",
      "movement_timestamp": 1554395972174,
      "movement_id": "d8f902be-f8c3-4f9c-ac66-67000510900d",
      "movement_type": "final_settlement",
      "trade_id": "3ad29e08-8b4f-435b-89aa-17b7a298b350",
      "deposit_reference_id": null,
      "withdrawal_request_id": null,
      "change": "-200",
      "parent_link_id": "53fe5944-12ff-4d17-ac0f-34530b184f7a"
    },
    {
      "run_id": "498",
      "movement_timestamp": 1554395972000,
      "movement_id": "c6af3d80-1aca-4280-b96b-a9b8d7ced46a",
      "movement_type": "deposit",
      "trade_id": null,
      "deposit_reference_id": "ebedc42f-85c3-4468-8894-1cb6f49f7a04",
      "withdrawal_request_id": null,
      "change": "10000",
      "parent_link_id": "27ebe256-fa77-4c27-b92e-111bc354be03"
    },
    {
      "run_id": "497",
      "movement_timestamp": 1554395972000,
      "movement_id": "c6af3d80-1aca-4280-b96b-a9b8d7ced46a",
      "movement_type": "withdrawal",
      "trade_id": null,
      "deposit_reference_id": null,
      "withdrawal_request_id": "100",
      "change": "-50",
      "parent_link_id": "8de019e4-f1fa-40af-9296-1ccda8f02abe"
    }
  ],
  "page": 1,
  "total_pages": 40
}

Returns the history of each itemized movement that has been applied to an account to lead up to its current balance.

Optional query parameters include:

Parameter Description Type
run_id A unique ID for the particular run string
movement_timestamp The timestamp of the specific movement timestamp
movement_id A unique ID for the specific account update string
movement_type The type of movement string
trade_id The unique identifier of the trade or loan that resulted in the movement, if the movement was due to a trade or loan
If a trade, this is equal to the trade_id field provided via the /trades
string
deposit_reference_id This is an external identifier associated with the deposit, if the movement was due to a deposit
This is equal to the reference_id field provided via the /deposits endpoint
string
withdrawal_request_id The withdrawal request ID, if the movement was due to a withdrawal
This is equal to the id field provided via the /withdrawals/requests endpoint
string
change The change due to the specific movement string
parent_link_id The identifier of the transaction that originated the movement string

Movement Type

Movement Description
collateralize_loan A movement related to an increase in collateral held for any open loan(s)
deposit A deposit of additional assets into Zero Hash
execution_fee A movement due to incurred execution fees related to your trading activity on a Zero Hash liquidity venue
final_settlement A movement due to the full delivery and final settlement of a trade
final_settlement_default A movement due to a financially-settled trade whose final settlement obligation could not be fully settled due to a default
final_settlement_default_fallback A movement due to the financial settlement for the portion of a physically-settled trade's final settlement obligation that was not fully delivered due to a default
final_settlement_default_partial A movement due to the partial physical delivery of a physically-settled trade whose final settlement obligation could not be fully delivered due to a default
initial_margin A movement related to an increase or decrease in collateral held for any open position(s)
interest_payment A payment of interest for a loan
loan_collateral_return A movement related to a decrease in collateral held for any open loan(s)
network_fee A blockchain network fee incurred due to an on-chain movement related to your wallet
principal_swap A transfer of principal and collateral assets to open a loan
repayment A transfer to return principal and collateral for a loan that has terminated
transfer An internal transfer to or from an account at Zero Hash
variation_margin A payment made or collected due to changes in the market value of the position since the trade was executed or since the previous time the position was marked to market
variation_margin_previous A payment made or collected to settle a previously outstanding variation margin obligation
withdrawal A processed withdrawal from Zero Hash
withdrawal_confirmed Reversal of the temporary hold due to a withdrawal being processed
withdrawal_pending Temporary hold whilst a withdrawal is being processed

POST /accounts/new

Sample Request

const postAccount = () => {
  const body = {
    participant_code: "PAR001",
    prefunded: false,
    account_label: "account-label"
  }

  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/accounts/new' + JSON.stringify(
    body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    'https://api.zerohash.com/accounts/new',
    options
  )
}
accounts = make_seed_request('POST', '/accounts/new', {})

Sample Response

{
  "message": {
    "participant_code": "PAR001",
    "account_group": "PLT001",
    "account_label": "account-label",
    "prefunded": false
  }
}

Allows a platform to specify that an account is either pre-funded or not. NOTE: this is only relevant to our Central Limit Order Book (CLOB).

Parameter Description Type
participant_code The code of the participant that owns the account string
account_label the platform-dictated account label for the account. If not filled, the account label will be the participant_code. string
prefunded indicates whether the participant has prefunded their account or not boolean

Movements

GET /movements

Sample Request

const getAccountMovements = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/movements?page=1&limit=3&account_id=e5e18303-a352-4c28-8dab-3779e66a659b' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    `https://api.zerohash.com/movements?page=1&limit=3&account_id=e5e18303-a352-4c28-8dab-3779e66a659b`,
    options
  )
}

Sample Response

{
  "message": [
    {
      "movement_timestamp": 1554395972174,
      "account_id": "e5e18303-a352-4c28-8dab-3779e66a659b",
      "movement_id": "ab938734-0aa6-4378-baa1-2cc56aeee757",
      "movement_type": "final_settlement",
      "transfer_type": null,
      "deposit_reference_id": null,
      "withdrawal_request_id": null,
      "parent_link_id": "f99411c3-5958-42f0-9ab7-d94d14221786",
      "trade_id": "951806f4-d3ba-42c4-96fe-8083cd3202cf",
      "change": "100"
    },
    {
      "movement_timestamp": 1554395972174,
      "account_id": "e5e18303-a352-4c28-8dab-3779e66a659b",
      "movement_id": "d8f902be-f8c3-4f9c-ac66-67000510900d",
      "movement_type": "final_settlement",
      "transfer_type": null,
      "deposit_reference_id": null,
      "withdrawal_request_id": null,
      "parent_link_id": "53fe5944-12ff-4d17-ac0f-34530b184f7a",
      "trade_id": "3ad29e08-8b4f-435b-89aa-17b7a298b350",
      "change": "-200"
    },
    {
      "movement_timestamp": 1554395972000,
      "account_id": "e5e18303-a352-4c28-8dab-3779e66a659b",
      "movement_id": "c6af3d80-1aca-4280-b96b-a9b8d7ced46a",
      "movement_type": "deposit",
      "transfer_type": null,
      "deposit_reference_id": "ebedc42f-85c3-4468-8894-1cb6f49f7a04",
      "withdrawal_request_id": null,
      "parent_link_id": "27ebe256-fa77-4c27-b92e-111bc354be03",
      "trade_id": null,
      "change": "10000"
    }
  ],
  "page": 1,
  "total_pages": 10
}

Returns movements that lead up to current account balance.

Optional query parameters include:

Parameter Description Type
movement_timestamp The timestamp of the specific movement timestamp
account_id A unique ID for the specific account timestamp
movement_id A unique ID for the specific account update string
movement_type The type of movement string
transfer_type The type of transfer string
trade_id The unique identifier of the trade or loan that resulted in the movement, if the movement was due to a trade or loan
If a trade, this is equal to the trade_id field provided via the /trades
string
deposit_reference_id This is an external identifier associated with the deposit, if the movement was due to a deposit
This is equal to the reference_id field provided via the /deposits endpoint
string
withdrawal_request_id The withdrawal request ID, if the movement was due to a withdrawal
This is equal to the id field provided via the /withdrawals/requests endpoint
string
change The change due to the specific movement string
parent_link_id The identifier of the transaction that originated the movement string

Movement Type

Movement Description
collateralize_loan A movement related to an increase in collateral held for any open loan(s)
deposit A deposit of additional assets into Zero Hash
execution_fee A movement due to incurred execution fees related to your trading activity on a Zero Hash liquidity venue
final_settlement A movement due to the full delivery and final settlement of a trade
final_settlement_default A movement due to a financially-settled trade whose final settlement obligation could not be fully settled due to a default
final_settlement_default_fallback A movement due to the financial settlement for the portion of a physically-settled trade's final settlement obligation that was not fully delivered due to a default
final_settlement_default_partial A movement due to the partial physical delivery of a physically-settled trade whose final settlement obligation could not be fully delivered due to a default
initial_margin A movement related to an increase or decrease in collateral held for any open position(s)
interest_payment A payment of interest for a loan
loan_collateral_return A movement related to a decrease in collateral held for any open loan(s)
network_fee A blockchain network fee incurred due to an on-chain movement related to your wallet
principal_swap A transfer of principal and collateral assets to open a loan
repayment A transfer to return principal and collateral for a loan that has terminated
transfer An internal transfer to or from an account at Zero Hash
variation_margin A payment made or collected due to changes in the market value of the position since the trade was executed or since the previous time the position was marked to market
variation_margin_previous A payment made or collected to settle a previously outstanding variation margin obligation
withdrawal A processed withdrawal from Zero Hash
withdrawal_confirmed Reversal of the temporary hold due to a withdrawal being processed
withdrawal_pending Temporary hold whilst a withdrawal is being processed
commission Commission charged on the trade
bank_fee Information field for platforms to provide if needed

Transfer Type

Transfer Description
trade_allocation A trade movement to customer account for settlement
commission_allocation A commission movement to customer account for settlement
commission_correction An adjustment to commission

Deposits

GET /deposits

const getDeposits = () => {
  const body = {}
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/deposits' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/deposits', options)
}
deposits = make_seed_request('GET', '/deposits', {})

Sample Response

{
  "message": [
    {
      "settle_timestamp": 1590663417000,
      "account_id": "80289ce5-072b-4739-929d-dcc5ccc542f3",
      "movement_id": "21bdbb11-712f-4cb7-a178-4f277c80cde0",
      "participant_code": "ABC123",
      "account_group": "00SCXM",
      "account_label": "general",
      "asset": "BTC",
      "amount": "4.0000",
      "reference_id": "408482348dcb0e0331a9148d50f8c76db08138f63fb1586fcfc45200a91ccc5f",
      "source": "tb1qne1pq8yampg83w4d5ywc79frdrub0az9eqpq9w",
      "received_address": "tb1qf9bd2891mfhhz87o6ibairn86tadctgcn822pl",
      "run_id": "12613"
    }
  ],
  "page": 1,
  "total_pages": 1
}

Returns an array of deposits associated with the participant requesting. If you'd like to view your customer deposits in addition to yours, use the include_customer_deposits query parameter.

Query parameters include:

Response:

Parameter Description Type
settle_timestamp The timestamp for when the deposit was credited to the participant - this is also the movement_timestamp timestamp
movement_id A unique ID for the specific account update string
account_id Unique ID of the specific account string
participant_code The participant that was credited with the deposit, e.g. ABCDEF string
account_group The account group associated with the account_id that received the deposit, e.g. 00SCXM for the Seed Digital Commodities Market account group string
account_label The account label associated with the account string
asset The asset code for the request, e.g. BTC string
amount The amount that was deposited into the account number
reference_id This is an external identifier associated with the deposit, which is context-specific depending on the asset type and deposit source - wire, transfer or on-chain transaction ID string
source The bank into which the fiat deposit was made or the blockchain address from which the crypto deposit came string
received_address The blockchain address to which the crypto deposit went string
run_id A unique ID for the particular run string

GET /deposits/digital_asset_addresses

const getDepositAddresses = () => {
  const body = {}
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/deposits/digital_asset_addresses' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/deposits/digital_asset_addresses',
    options
  )
}
depositAddresses = make_seed_request('GET', '/deposits/digital_asset_addresses', {})

Sample Response

{
  "message": [
    {
      "created_at": 1561996924964,
      "address": "2NCgV7BXXafJZ86utcYFs5m3tCpkcpLafeG",
      "participant_code": "ABCDEF",
      "asset": "BTC"
    },
    {
      "created_at": 1561996924964,
      "address": "0xe01ed9e684de649bfec799cd79f6c27335c23cb9",
      "participant_code": "ABCDEF",
      "asset": "ETH"
    }
  ]
}

Returns an array of addresses associated with a participant's digital asset wallet. In order to GET deposit addresses for a participant_code other than yourself, you must have the submits_platform_withdrawals_for relationship against said participant_code. Refer here for more information on relationship types.

Query parameters include:

Response:

Parameter Description Type
created_at The timestamp for when the address was created timestamp
address The digital wallet address string
asset The asset code for the request, e.g. BTC string
participant_code The participant the request belongs to, e.g. ABCDEF string

POST /deposits/digital_asset_addresses

const postDepositAddress = () => {
  const body = { participant_code: 'ABCDEF', asset: 'BTC' }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/deposits/digital_asset_addresses' + JSON.stringify(
    body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    'https://api.zerohash.com/deposits/digital_asset_addresses',
    options
  )
}
depositAddress = make_seed_request('POST', '/deposits/digital_asset_addresses', {})

Sample Request

{
  "participant_code": "ABCDEF",
  "asset": "BTC"
}

Sample Response

{
  "message": {
    "created_at": 1561996924964,
    "address": "2NCgV7BXXafJZ86utcYFs5m3tCpkcpLafeG",
    "participant_code": "ABCDEF",
    "account_label": "general",
    "asset": "BTC"
  }
}

Creates a new digital wallet deposit address for the asset and participant_code provided. In order to request a deposit address for a participant_code other than yourself, you must have the submits_platform_withdrawals_for relationship against said participant_code. Refer here for more information on relationship types.

Parameter Description Type
participant_code The participant code to create an address for string
asset The asset code to make an address in, e.g. BTC string
account_label (optional) The account label associated with the deposit per participant and asset string

Response:

Parameter Description Type
created_at The timestamp for when the address was created timestamp
address The digital wallet address string
asset The asset code tied to the address, e.g. BTC string
participant_code The participant the address belongs to, e.g. ABCDEF string
account_label The account label associated with the deposit per participant and asset, e.g. general string

GET /deposits/fiat_accounts

const getFiatDepositAccounts = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/deposits/fiat_accounts' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/deposits/fiat_accounts', options)
}
zeroHashAccounts = make_seed_request('GET', '/deposits/fiat_accounts', {})

Sample Response

{
  "message": {
    "USD": [
      {
        "type": "united_states_wire",
        "shortName": "BMO Harris",
        "bankName": "BMO Harris Bank N.A.",
        "bankPhysicalAddress": "123 Nowhere St.",
        "accountNumber": "123-123-4",
        "routingNumber": "07102343",
        "recipientName": "Zero Hash LLC",
        "recipientPhysicalAddress": "123 Nowhere St.",
        "reference": "Your Participant Code"
      },
      { ... }
    ],
    "EUR": [ ... ]
  }
}

Retrieves a list of all fiat deposit accounts available to you per fiat currency. The account details are keyed by currency code. Note: your participant code is provided as the reference field for each bank account. You must include this with any deposit to ensure that funds can be allocated correctly to your participant.

POST /deposits/fund

const postDepositsFund = () => {
  const body = { participant_code: 'ABCDEF', asset: 'USD', amount: '2.99' }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/deposits/fund' + JSON.stringify(
    body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    'https://api.zerohash.com/deposits/fund',
    options
  )
}
depositsFund = make_seed_request('POST', '/deposits/fund', {})

Sample Request

{
  "participant_code": "ABCDEF",
  "asset": "USD",
  "amount": "1.00"
}

Sample Response

{
  "message": {
    "amount": "1.00",
    "participant_code": "ABCDEF",
    "account_group": "ABCDEF",
    "account_label": "general",
    "account_type": "available",
    "asset": "USD",
    "reference_id": "21bdbb11-712f-4cb7-a178-4f277c80cde0"
  }
}

Use this endpoint to fund a specified fiat account in Zero Hash’s CERT environment. This is NOT available in PROD. Using this endpoint is helpful when completing an integration to Zero Hash and wanting to enable end-to-end testing.

Parameter Description Type
participant_code (required) This can be a linked participant to the Platform or the Platform can provide 00SCXM when looking to fund float accounts. string
asset (required) The fiat asset that is looking to be funded. Right now this will only support USD. string
amount (required) The amount that the Platform is looking to fund. This can only go out to two decimal places. string
account_label (optional) This will default to general if not provided. Platforms may want to specify a specific account_label when looking to fund their rewards or awards float account. string

Please note that Zero Hash will default the account label to be the platform_code in the background to ensure the Platform is only funding accounts they manage.

Response:

Parameter Description Type
participant_code The code of the participant that owns the account string
asset The asset code for the specific account, e.g. USD string
amount The amount that was deposited into the account string
account_label The account label associated with the account string
account_group The group that the account is a part of string
account_type 'available', 'collateral', 'payable', 'receivable' or 'collateral_deficiency' string
reference_id This is an external identifier associated with the deposit, which is context-specific depending on the asset type and deposit source - wire, transfer or on-chain transaction ID string

Withdrawals

GET /withdrawals/requests

const getWithdrawalRequests = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/requests' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/withdrawals/requests', options)
}
withdrawalRequests = make_seed_request('GET', '/withdrawals/requests', {})

Sample Response

{
  "message": [
    {
      "id": 78,
      "withdrawal_account_id": 51,
      "participant_code": "ABCDEF",
      "requestor_participant_code": "ABCDEF",
      "requested_amount": "23",
      "settled_amount": "21",
      "status": "APPROVED",
      "asset": "BTC",
      "account_group": "00SCXM",
      "transaction_id": null,
      "requested_timestamp": 1554395972174,
      "gas_price": null,
      "client_withdrawal_request_id": null,
      "on_chain_status": "PENDING",
      "fee_amount": "0.003163149641603118"
    }
  ],
  "page": 1,
  "total_pages": 1
}

Returns an array of all withdrawal requests created by users as part of your participant.

Query parameters include:

Response:

Parameter Description Type
id The withdrawal request ID number
client_withdrawal_request_id A unique identifier for the withdrawal, generally produced by the Platform on which the trade was executed
Note: this must be unique, per platform, per 24 hour period
string
withdrawal_account_id The ID of the withdrawal account the address belongs to number
asset The asset code for the request, e.g. BTC string
participant_code The participant the request belongs to, e.g. ABCDEF string
requestor_participant_code The participant code of the requestor, e.g. ABCDEF string
account_group The account group the request was made against, e.g. 00SCXM for the Seed Digital Commodities Market account group string
requested_amount The initially requested amount, e.g. 100.10 string
settled_amount The settled amount. This can be less than or equal to the requested_amount, e.g. 99 string or null
transaction_id The on-chain transaction id once the withdrawal has been confirmed string or null
status The current status of the withdrawal request string
requested_timestamp The timestamp for when the withdrawal request was requested timestamp
gas_price The transaction fee payable on the Ethereum network
If the asset is not an ERC-20 token, this field will always be null
string or null
on_chain_status The status of the withdrawal on the blockchain. Could be PENDING or CONFIRMED more details here. string
fee_amount will return the network fee amount string

GET /withdrawals/requests/:id

const getWithdrawalRequests = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/requests/78' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/withdrawals/requests/78',
    options
  )
}
withdrawalRequests = make_seed_request('GET', '/withdrawals/requests/78', {})

Sample Response

{
  "message": [
    {
      "id": 78,
      "withdrawal_account_id": 51,
      "participant_code": "ABCDEF",
      "requestor_participant_code": "ABCDEF",
      "requested_amount": "23",
      "settled_amount": "21",
      "status": "APPROVED",
      "asset": "BTC",
      "account_group": "00SCXM",
      "transaction_id": null,
      "requested_timestamp": 1554395972174,
      "gas_price": null,
      "client_withdrawal_request_id": null,
      "on_chain_status": "PENDING",
      "fee_amount": "0.003163149641603118"
    }
  ]
}

Returns a specific withdrawal request associated with your participant or platform.

See GET /withdrawals/requests for response field descriptions.

POST /withdrawals/requests

Sample Request

const postWithdrawalRequest = () => {
  const body = {
    withdrawal_account_id: 123,
    participant_code: "ABCDEF",
    amount: "20",
    asset: "BTC",
    account_group: "00SCXM"
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/withdrawals/requests' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/withdrawals/requests`, options)
}
resp = make_seed_request('POST', '/withdrawals/requests', {})

Sample Response

{
  "message": {
    "id": 117,
    "withdrawal_account_id": 146,
    "participant_code": "ABCDEF",
    "requestor_participant_code": "ABCDEF",
    "account_group": "00SCXM",
    "requested_amount": "20",
    "settled_amount": null,
    "status": "APPROVED",
    "asset": "BTC",
    "requested_timestamp": 1561996924964,
    "gas_price": null,
    "client_withdrawal_request_id": null,
    "on_chain_status": "PENDING",
    "fee_amount": "0.003163149641603118"
  }
}

Creates new withdrawal requests to be settled. Withdrawal requests created through the API go directly into an APPROVED state. To retrieve withdrawal account IDs use the GET /withdrawals/digital_asset_addresses and GET /withdrawals/fiat_accounts endpoints.

There are 3 ways to submit withdrawal requests:

  1. The first, standard method uses a withdrawal_account_id to choose the location to withdrawal to, which can be for a fiat currency or a digital asset. The account must be in an APPROVED state before submitting withdrawal requests to it.
  2. The second method allows for submitting a digital asset address instead of the withdrawal_account_id. When POSTing an address, Zero Hash will first scan to see if you already have an existing withdrawal_account_id for that destination, and if not, it will create one automatially and provide you the withdrawal_account_id in response. This is not available as standard. Please contact us if you'd like to learn more about this option.
  3. The third method allows for submitting a fiat withdrawal account{} instead of the withdrawal_account_id. When POSTing an account{}, Zero Hash will first scan to see if you already have an existing withdrawal_account_id for that destination, and if not, it will create one automatially and provide you the withdrawal_account_id in response. This is not available as standard. Please contact us if you'd like to learn more about this option.

Request body:

Parameter Description Type
client_withdrawal_request_id A unique identifier for the withdrawal, generally produced by the Platform on which the trade was executed
Note: this must be unique, per platform, per 24 hour period
string
withdrawal_account_id The whitelisted withdrawal account or address to withdraw funds to
Note: only one of withdrawal_account_id, address or account{} can be submitted per withdrawal, but Zero Hash will always respond with withdrawal_account_id
string
address The digital asset address to withdraw funds to, which may or may not already exist in Zero Hash as an approved withdrawal_account_id
Note: only one of withdrawal_account_id, address or account{} can be submitted per withdrawal, but Zero Hash will always respond with withdrawal_account_id
string
account{} The fiat account to withdraw funds to, which may or may not already exist in Zero Hash as an approved withdrawal_account_id
Note: only one of withdrawal_account_id, address or account{} can be submitted per withdrawal, but Zero Hash will always respond with withdrawal_account_id
object
participant_code The participant code against whom the withdrawal will be made string
account_group The account group to withdraw against, e.g. 00SCXM for the Seed Digital Commodities Market account group string
account_label The account label associated with the account string
amount The amount to withdraw string
asset The asset code for the withdrawal request, e.g. BTC string
destination_tag For tag-based assets, please provide the memo id/destination tag value in this field. For more information on when and how to populate this field, please refer here string
no_destination_tag The value should be true or false. For more information on when and how to populate this field, please refer here boolean
input_data Applicable only for smart contract executions on the Ethereum blockchain. This is the ABI encoding of the function and its arguments in RLP format. string

Account field shape:

Parameter Description Type
name The nickname given to the withdrawal account
Note: Zero Hash will append the last 4 digits of the account number to this when saving it
string
limit The limit applied to the account on a per-withdrawal basis number
type The type of account: REAL_TIME_FIAT for 24/7 USD withdrawals, DOMESTIC_FIAT for US wires or INTERNATIONAL_FIAT for international wires string
beneficiary_name The owner of the account at the withdrawal destination string
account_number The unique IBAN or account number for the final withdrawal destination string
bank_name The name of the destination financial institution string
routing_number For US wires, the ABA routing number identifies the destination financial institution string
swift_code SWIFT code, if applicable string
recipient_instructions Any additional instructions on the account string
intermediary_
bank_name
Intermediary bank name, if applicable string
intermediary_
bank_code_type
Intermediary bank identifier code type, if applicable
Options include SWIFT
string
intermediary_
bank_code
Intermediary bank identifier that corresponds to intermediary_bank_code_type, if applicable string
intermediary_
bank_account_number
Intermediary bank IBAN or account number, if applicable string
correspondent_
bank_name
Correspondent bank name, if applicable string
correspondent_
bank_code_type
Correspondent bank identifier code type, if applicable
Options include SWIFT
string
correspondent_
bank_code
Correspondent bank identifier that corresponds to correspondent_bank_code_type, if applicable string
correspondent_
bank_account_number
Correspondent bank IBAN or account number, if applicable string

DELETE /withdrawals/requests/:id

const deleteWithdrawalRequest = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'DELETE' + '/withdrawals/requests' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    json: true
  }
  const withdrawalRequestId = 1

  return request.delete(
    `https://api.zerohash.com/withdrawals/requests/${withdrawalRequestId}`,
    options
  )
}
resp = make_seed_request('DELETE', '/withdrawals/requests/1', {})

Sample Response

{
  "message": {
    "id": 1,
    "withdrawal_account_id": 146,
    "participant_code": "ABCDEF",
    "requestor_participant_code": "ABCDEF",
    "requested_amount": "20",
    "account_group": "00SCXM",
    "settled_amount": null,
    "status": "REJECTED",
    "asset": "BTC",
    "requested_timestamp": 1561996924964,
    "gas_price": null,
    "client_withdrawal_request_id": null,
    "on_chan_status": null,
    "fee_amount": "0.003163149641603118"
  }
}

Rejects a pending withdrawal request.

GET /withdrawals/digital_asset_addresses

const getWithdrawalAddresses = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/digital_asset_addresses' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    json: true
  }

  return request.get(
    `https://api.zerohash.com/withdrawals/digital_asset_addresses?participant_code=YOUR_PARTICIPANT_CODE`,
    options
  )
}
withdrawalAddresses = make_seed_request('GET', '/withdrawals/digital_asset_addresses?participant_code=YOUR_PARTICIPANT_CODE', {})

Sample Response

{
  "message": [
    {
      "withdrawal_account_id": 123,
      "name": "Fund ABC Wallet",
      "address": "M9zjMhjaPfwaeyeH2SY6aWyGqdTS9feg8Z",
      "status": "APPROVED",
      "limit": 1000,
      "asset": "LTC",
      "last_update": 1554395972174,
      "submitted_address": "33nb3pKcSZ69rUNNvZYkksisWvrzCmi3Jt",
      "participant_code": "ABCDEF"
    }
  ],
  "page": 1,
  "total_pages": 1
}

Returns an array of all withdrawal addresses created by users as part of your participant.

Query parameters include:

Response:

Parameter Description Type
withdrawal_account_id The ID of the withdrawal account the address belongs to number
name The nickname the address was given when it was created string
address The blockchain address string
status The approval status of the address string
asset The asset code for the specific account, e.g. BTC string
limit The limit applied to the account on a per-withdrawal basis number
last_update Timestamp for when the withdrawal address last update timestamp
submitted_address This is the original value for an address submitted by you, that was converted into a newer format supported by Zero Hash - this will be null if no conversion is necessary string
participant_code The participant the request belongs to, e.g. ABCDEF string

GET /withdrawals/digital_asset_addresses/:id

const getWithdrawalAddresses = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/digital_asset_addresses/:id' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/withdrawals/digital_asset_addresses/:id',
    options
  )
}
withdrawalAddresses = make_seed_request('GET', '/withdrawals/digital_asset_addresses/:id', {})

Sample Response

{
  "message": {
    "withdrawal_account_id": 123,
    "name": "Fund ABC Wallet",
    "address": "M9zjMhjaPfwaeyeH2SY6aWyGqdTS9feg8Z",
    "status": "APPROVED",
    "limit": 1000,
    "asset": "LTC",
    "last_update": 1554395972174,
    "submitted_address": "33nb3pKcSZ69rUNNvZYkksisWvrzCmi3Jt",
    "participant_code": "ABCDEF"
  }
}

Returns a specific crypto withdrawal account associated with your participant or platform.

See GET /withdrawals/digital_asset_addresses for response field descriptions.

GET /withdrawals/fiat_accounts

const getFiatWithdrawalAccounts = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/fiat_accounts' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/withdrawals/fiat_accounts',
    options
  )
}
zeroHashAccounts = make_seed_request('GET', '/withdrawals/fiat_accounts', {})

Sample Response

{
  "message": [
    {
      "withdrawal_account_id": 286,
      "name": "Primary (1234)",
      "status": "PENDING_CREATION",
      "asset": "USD",
      "limit": 750000,
      "type": "DOMESTIC_FIAT",
      "beneficiary_name": "John Doe",
      "account_number": "1231234",
      "bank_name": "BMO Harris",
      "routing_number": "07102343",
      "swift_code": null,
      "recipient_instructions": null,
      "intermediary_bank_name": null,
      "intermediary_bank_code_type": null,
      "intermediary_bank_code": null,
      "intermediary_bank_account_number": null,
      "correspondent_bank_name": null,
      "correspondent_bank_code_type": null,
      "correspondent_bank_code": null,
      "correspondent_bank_account_number": null,
      "last_update": 1571175076187,
      "participant_code": "ABCDEF"
    },
    { ... }
  ],
  "page": 1,
  "total_pages": 1
}

Retrieves a list of all whitelisted fiat withdrawal accounts.

Parameter Description Type
withdrawal_account_id The ID of the withdrawal account number
name The nickname given to the withdrawal account string
status The approval status of the withdrawal account string
asset The asset code for the specific withdrawal account, e.g. USD string
limit The limit applied to the account on a per-withdrawal basis number
type The type of account: REAL_TIME_FIAT for 24/7 USD withdrawals, DOMESTIC_FIAT for US wires or INTERNATIONAL_FIAT for international wires string
beneficiary_name The owner of the account at the withdrawal destination string
account_number The unique IBAN or account number for the final withdrawal destination string
bank_name The name of the destination financial institution string
routing_number For US wires, the ABA routing number identifies the destination financial institution string
swift_code SWIFT code, if applicable string
recipient_instructions Any additional instructions on the account string
intermediary_
bank_name
Intermediary bank name, if applicable string
intermediary_
bank_code_type
Intermediary bank identifier code type, if applicable
Options include SWIFT
string
intermediary_
bank_code
Intermediary bank identifier that corresponds to intermediary_bank_code_type, if applicable string
intermediary_
bank_account_number
Intermediary bank IBAN or account number, if applicable string
correspondent_
bank_name
Correspondent bank name, if applicable string
correspondent_
bank_code_type
Correspondent bank identifier code type, if applicable
Options include SWIFT
string
correspondent_
bank_code
Correspondent bank identifier that corresponds to correspondent_bank_code_type, if applicable string
correspondent_
bank_account_number
Correspondent bank IBAN or account number, if applicable string
last_update Timestamp for when the withdrawal address last update timestamp
submitted_address This is the original value for an address submitted by you, that was converted into a newer format supported by Zero Hash - this will be null if no conversion is necessary string
participant_code The participant the request belongs to, e.g. ABCDEF string

GET /withdrawals/fiat_accounts/:id

const getFiatWithdrawalAccounts = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/fiat_accounts/:id' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/withdrawals/fiat_accounts/:id',
    options
  )
}
zeroHashAccounts = make_seed_request('GET', '/withdrawals/fiat_accounts/:id', {})

Sample Response

{
  "message": {
    "withdrawal_account_id": 286,
    "name": "Primary (1234)",
    "status": "PENDING_CREATION",
    "asset": "USD",
    "limit": 750000,
    "type": "DOMESTIC_FIAT",
    "beneficiary_name": "John Doe",
    "account_number": "1231234",
    "bank_name": "BMO Harris",
    "routing_number": "07102343",
    "swift_code": null,
    "recipient_instructions": null,
    "intermediary_bank_name": null,
    "intermediary_bank_code_type": null,
    "intermediary_bank_code": null,
    "intermediary_bank_account_number": null,
    "correspondent_bank_name": null,
    "correspondent_bank_code_type": null,
    "correspondent_bank_code": null,
    "correspondent_bank_account_number": null,
    "last_update": 1571175076187,
    "participant_code": "ABCDEF"
  }
}

Returns a specific fiat withdrawal account associated with your participant or platform.

See GET /withdrawals/fiat_accounts for response field descriptions.

Withdrawal Request Status

Status Description
PENDING The request has been created and is pending approval from users
APPROVED The request is approved but not settled
REJECTED The request is rejected and in a terminal state
SETTLED The request was settled and sent for confirmation onchain if a digital asset

Withdrawal Account Status

Status Description
PENDING_CREATION Account is awaiting approval
APPROVED The account is approved for use
REJECTED The account was rejected for use
DELETED The account was deleted, removing it from view in the portal
PENDING_CHANGE DEPRECATED The address is awaiting a change approval for either unlocking or changing the limit

GET /withdrawals/locked_network_fee

const getLockedNetworkFee = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/locked_network_fee' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/withdrawals/locked_network_fee?participant_code=CUST01&account_group=PLAT01&amount=.023&destination_tag=&asset=ETH&withdrawal_address=0x48b358a64eb0cDfeD6f369B7610Be84cBC6D3Ad7',
    options
  )
}
res = make_seed_request('GET', '/withdrawals/locked_network_fee?participant_code=CUST01&account_group=PLAT01&amount=.023&destination_tag=&asset=ETH&withdrawal_address=0x48b358a64eb0cDfeD6f369B7610Be84cBC6D3Ad7', {})

Sample Response

{
    "message": {
        "withdrawal_quote_id": "b30739eb-173d-45f9-a03e-281e7c4db22c",
        "withdrawal_account_id": "",
        "withdrawal_address": "0x48b358a64eb0cDfeD6f369B7610Be84cBC6D3Ad7",
        "destination_tag": "",
        "amount": "0.023",
        "amount_notional": "30.15",
        "max_amount": false,
        "network_fee": "0.000546004133871",
        "network_fee_notional": "0.72",
        "net_withdrawal_quantity": "0.022453995866129",
        "net_withdrawal_notional": "29.44",
        "asset": "ETH",
        "participant_code": "CUST01",
        "account_group": "PLAT01",
        "account_label": "general"
    }
}

GET /withdrawals/locked_network_fee and POST /withdrawals/execute can be used to create a withdrawal locked network fee quote and execute it on-chain. To use these endpoints a Platform needs to be configured for netted withdrawals, which is a new withdrawal fee payor setting.

All withdrawals processed using these endpoints will have the locked network fee deducted from the withdrawal amount that is actually processed on-chain. Additionally all network fees are quoted as the asset being requested to be withdrawn. Network fees are locked for 30 seconds, after this time if a Platform tries to execute the locked network fee quote an error response will be returned.

Query parameters include:

For more details on how the endpoints function see here.

Response:

Parameter Description Type
account_group The account_group for the source account that the withdrawal was processed from. string
account_label The account_label for the source account that the withdrawal was processed from. string
amount The requested withdrawal amount. string
amount_notional The requested withdrawal amount notional value. string
asset The asset that has been withdrawn. string
destination_tag The destination tag for the withdrawal. string
no_destination_tag If a destination tag is specified for the withdrawal. boolean
max_amount The max amount flag. string
net_withdrawal_notional amount minus network_fee notional value. string
net_withdrawal_quantity amount minus network_fee, in terms of quantity. string
network_fee The network fee quantity being deducted from the requested withdrawal amount. string
network_fee_notional The network fee notional value. string
participant_code The participant that requested the withdrawal. string
withdrawal_address The on-chain address that received the crypto asset. string
withdrawal_quote_id The unique ID that is associated with the locked network fee. string
withdrawal_account_id The withdrawal account ID that is associated with the destination address. string

POST /withdrawals/execute

const postWithdrawalExecuteRequest = () => {
  const body = {
    withdrawal_quote_id: "b30739eb-173d-45f9-a03e-281e7c4db22c"
  }

  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/withdrawals/execute' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/withdrawals/execute`, options)
}
resp = make_seed_request('POST', '/withdrawals/execute', {})

Sample Response

{
    "message": {
        "request_id": "c9d19acc-96bc-4c29-9708-50912fd174cf",
        "withdrawal_quote_id": "b30739eb-173d-45f9-a03e-281e7c4db22c",
        "withdrawal_request_id": "58672",
        "participant_code": "CUST01",
        "account_group": "PLAT01",
        "account_label": "general",
        "withdrawal_address": "0x48b358a64eb0cDfeD6f369B7610Be84cBC6D3Ad7",
        "destination_tag": "",
        "asset": "ETH",
        "amount": "0.023",
        "amount_notional": "30.15",
        "network_fee": "0.000546004133871",
        "network_fee_notional": "0.72",
        "on_chain_status": "PENDING"
    }
}

This endpoint is used to execute a locked network fee quote. This will tell Zero Hash to process the withdrawal on-chain.

Request body:

Parameter Description Type
withdrawal_quote_id The unique ID that is associated with the locked network fee. This will be required to execute the withdrawal. string

Response:

Parameter Description Type
account_group The account_group for the source account that the withdrawal was processed from. string
account_label The account_label for the source account that the withdrawal was processed from. string
amount The requested withdrawal amount. string
amount_notional The requested withdrawal amount notional value. string
asset The asset that has been withdrawn. string
destination_tag The destination tag for the withdrawal. string
no_destination_tag If a destination tag is specified for the withdrawal. boolean
network_fee The network fee quantity being deducted from the requested withdrawal amount. string
network_fee_notional The network fee notional value. string
on_chain_status The status of the withdrawal on the blockchain. Could be PENDING or CONFIRMED more details here. string
participant_code The participant that requested the withdrawal. string
request_id The unique Id that is associated with this http request. string
withdrawal_address The on-chain address that received the crypto asset. string
withdrawal_quote_id The unique ID that is associated with the locked network fee. string
withdrawal_request_id The unique Id that is associated with this withdrawal request. string

GET /withdrawals/estimate_network_fee

const getEstimateNetworkFee = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/withdrawals/estimate_network_fee' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(
    'https://api.zerohash.com/withdrawals/estimate_network_fee',
    options
  )
}
estimateNetworkFee = make_seed_request('GET', '/withdrawals/estimate_network_fee', {})

Sample Response

{
  "message": {
        "underlying": "BTC",
        "quoted_currency": "USD",
        "network_fee_asset": "BTC",
        "network_fee_quantity": "0.000172825",
        "total_notional": "3.3733791241663290125"
    }
}

Retrive the estimate network fee. The following query parameters are required:

Optional query parameters include:

Parameter Description Type
underlying The asset being valued string
quoted_currency The asset in which the underlying is being valued string
network_fee_asset The network fee asset string
network_fee_quantity The quantity of network fee string
total_notional fee_amount x (index price for fee_currency quoted in quoted_currency) string

Transfers

GET /transfers

const getTransfers = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/transfers' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/transfers', options)
}
resp = make_seed_request('GET', '/transfers', {})

Sample Response

{
  "message": [
    {
      "id": 39,
      "client_transfer_id" : "5fed7a1d-1cd3-4be7-9d63-dd67805d441d",
      "created_at": "2020-09-01T20:53:31.653Z",
      "updated_at": "2020-09-01T20:53:31.653Z",
      "status": "settled",
      "from_participant_code": "ABC123",
      "from_account_group": "UNALLOCATED",
      "from_account_label": "general",
      "to_participant_code": "DEMO01",
      "to_account_group": null,
      "to_account_label": "general",
      "asset": "BTC",
      "amount": "20.00",
      "movement_id": "1902a0eb-a925-4d08-bcad-ea8ed4696a24",
      "admin_transfer": true
    },
    {
      "id": 38,
      "client_transfer_id": null,
      "created_at": "2020-09-01T20:53:31.406Z",
      "updated_at": "2020-09-01T20:53:31.406Z",
      "status": "approved",
      "from_participant_code": "ABC123",
      "from_account_group": "UNALLOCATED",
      "from_account_label": "general",
      "to_participant_code": "ABC123",
      "to_account_group": "XYZ456",
      "to_account_label": "general",
      "asset": "USD",
      "amount": "100.00",
      "movement_id": null,
      "admin_transfer": false
    }
  ],
  "page": 1,
  "total_pages": 1
}

Returns an array of all transfers requests made to or from your participant, or to or from your platform's account group.

Query parameters include:

Response:

Parameter Description Type
id The transfer request ID number
client_transfer_id Optional unique identifier for the transfer.
Note: this must be unique, per platform, per 72 hour period
string
created_at The timestamp when the transfer request was requested timestamp
updated_at The timestamp when the transfer request was last updated timestamp
status The current status of the transfer request string
from_participant_code The source participant for the transfer to, e.g. ABCDEF string
from_account_group The source account group for the transfer, e.g. ABCDEF
Note: this may be null if the requesting participant is not authorized to see the source account group
string
from_account_label The source account label for the transfer, e.g. general string
to_participant_code The destination participant for the transfer, e.g. ABCDEF string
to_account_group The destination account group for the transfer, e.g. ABCDEF
Note: this may be null if the requesting participant is not authorized to see the destination account group
string
to_account_label The destination account label for the transfer, e.g. general string
asset The asset code for the request, e.g. USD string
amount The amount or quantity transferred, e.g. 100 string
movement_id A unique ID for the specific account update
Note: this will be null until the transfer updates to settled
string

Transfer Request Status

Status Description
pending The request has been created and is pending approval from users
approved The request is approved but not settled
canceled The request is canceled and in a terminal state
rejected The request is rejected and in a terminal state
settled The request was settled and is in a terminal state

GET /transfers/:id

const getTransfers = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/transfers/39' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/transfers/39', options)
}
resp = make_seed_request('GET', '/withdrawals/requests/39', {})

Sample Response

{
  "message": {
      "id": 39,
      "client_transfer_id": null,
      "created_at": "2020-09-01T20:53:31.653Z",
      "updated_at": "2020-09-01T20:53:31.653Z",
      "status": "settled",
      "from_participant_code": "ABC123",
      "from_account_group": "UNALLOCATED",
      "to_participant_code": "DEMO01",
      "to_account_group": null,
      "asset": "BTC",
      "amount": "20.00",
      "movement_id": "1902a0eb-a925-4d08-bcad-ea8ed4696a24",
      "admin_transfer": true
    }
}

Returns single transfer made to or from your participant, or to or from your platform's account group.

See GET /transfers for response field descriptions.

POST /transfers

const postTransfers = () => {
  const body = {
    from_participant_code: "ABC123",
    from_account_group: "UNALLOCATED",
    to_participant_code: "DEMO01",
    to_account_group: "UNALLOCATED",
    asset: "USD",
    amount: "1"
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/transfers' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post('https://api.zerohash.com/transfers', options)
}
resp = make_seed_request('POST', '/transfers', {})

Creates new transfer request. Note: you can only submit transfers between your own accounts. To submit transfers on behalf of others, you need the submits_platform_transfers_for relationship. Transfer requests created through the API go directly into an APPROVED state.

Request body:

Parameter Description Type
client_transfer_id Optional unique identifier for the transfer.
Note: this must be unique, per platform, per 72 hour period
string
from_participant_code The source participant for the transfer to, e.g. ABCDEF string
from_account_group The source account group for the transfer, e.g. ABCDEF string
from_account_label The source account label for the transfer, e.g. general string
to_participant_code The destination participant for the transfer, e.g. ABCDEF string
to_account_group The destination account group for the transfer, e.g. ABCDEF string
to_account_label The destination account label for the transfer, e.g. general string
asset The asset code for the request, e.g. USD string
amount The amount or quantity transferred, e.g. 100 string
client_transfer_id string

Sample Response

{
  "message": [
    {
      "id": 39,
      "client_transfer_id": null,
      "created_at": "2020-09-01T20:53:31.653Z",
      "updated_at": "2020-09-01T20:53:31.653Z",
      "status": "settled",
      "from_participant_code": "ABC123",
      "from_account_group": "UNALLOCATED",
      "from_account_label": "general",
      "to_participant_code": "DEMO01",
      "to_account_group": "UNALLOCATED",
      "to_account_label": "general",
      "asset": "BTC",
      "amount": "20.00",
      "movement_id": "1902a0eb-a925-4d08-bcad-ea8ed4696a24",
      "admin_transfer": true
    }
  ]
}

See GET /transfers for response field descriptions.

Participants

GET /participants

const getParticipants = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/participants' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/participants', options)
}
resp = make_seed_request('GET', '/participants', {})

Sample Response

{
  "message": [
    {
      "participant_code": "123XYZ",
      "custodian_participant_code": "CUST01",
      "participant_name": "Trading Firm LLC",
      "credit_limit": "50000",
      "status": "approved",
      "email": "customer@gmail.com",
      "reason_code": "compliance_issue",
      "updated_at": 1680643465352
    },
    {
      "participant_code": "ABC456",
      "participant_name": "Lots of Capital LLC",
      "credit_limit": null,
      "status": "approved",
      "email": null,
      "reason_code": null,
      "updated_at": 1680643465352
    }
  ],
  "page": 1,
  "total_pages": 1,
  "page_size": 50,
  "count": 2
}

Returns a list of all participants to which you are associated.

Query parameters include:

Response parameters listed below

Parameter Description Type
participant_code Unique participant code string
custodian_participant_code Unique participant code of the associated custodian string
participant_name Name of participant string
credit_limit Client-determined credit limit. used purely for reporting purposes at this time string
email Email associated with the participant. If the participant is institutional, this field will be null string
status The current status of the participant. read more about statuses here string
reason_code (optional) if the participant has changed statuses, the reason code will show compliance_issue, user_request, or risk_cleared string
updated_at Last update timestamp number

GET /participants/:email

const getParticipants = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/participants/{email}' + '{}'
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get('https://api.zerohash.com/participants/{email}', options)
}
resp = make_seed_request('GET', '/participants/{email}', {})

Sample Response

{
  "message": {
    "participant_code": "123XYZ",
    "email": "customer@gmail.com"
  }
}

Returns a participant to which you are associated by an email. As an alternative to using the email query parameter described above within the GET /participants endpoint, this is a lighter-weight and dedicated endpoint to filter participants by email.

Query parameters include:

Response parameters listed below

Parameter Description Type
participant_code Unique participant code string
email Email associated with the participant string

POST /participants/customers/new

const postParticipantCustomer = () => {
  const body = {
    request_id: '7fbab305-2679-4279-808b-9b7a63a55c85',
    first_name: 'John',
    last_name: 'Smith',
    email: 'email-example@mail.com',
    phone_number: '15557778888',
    address_one: '1 Main St.',
    address_two: 'Suite 1000',
    city: 'Chicago',
    state: 'IL',
    zip: '12345',
    country: 'United States',
    date_of_birth: '1985-09-02',
    citizenship: 'United States',
    tax_id: '123456789',
    risk_rating: 'low',
    kyc: 'pass',
    kyc_timestamp: 1603378501285,
    sanction_screening: 'pass',
    sanction_screening_timestamp: 1603378501285,
    signed_timestamp: 1603378501286,
    metadata: {}
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/participants/customers/new' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/customers/new`,
    options
  )
}
resp = make_seed_request('POST', '/participants/customers/new', {})

Sample Request

{
  "request_id": "7fbab305-2679-4279-808b-9b7a63a55c85",
  "first_name": "John",
  "last_name": "Smith",
  "email": "email-example@mail.com",
  "phone_number": "15557778888",
  "address_one": "1 Main St.",
  "address_two": "Suite 1000",
  "city": "Chicago",
  "state": "IL",
  "zip": "12345",
  "country": "United States",
  "date_of_birth": "1985-09-02",
  "citizenship": "United States",
  "tax_id": "123456789",
  "risk_rating": "low",
  "kyc": "pass",
  "kyc_timestamp": 1603378501285,
  "sanction_screening": "pass",
  "sanction_screening_timestamp": 1603378501285,
  "signed_timestamp": 1603378501286,
  "metadata": {}
}

Sample Response

{
  "message": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "email-example@mail.com",
    "address_one": "1 Main St.",
    "address_two": "Suite 1000",
    "country": "United States",
    "state": "IL",
    "city": "Chicago",
    "zip": "12345",
    "date_of_birth": "1985-09-02",
    "citizenship": "United States",
    "tax_id": "123456789",
    "id_number_type": null,
    "id_number": null,
    "non_us_other_type": null,
    "id_issuing_authority": null,
    "risk_rating": "low",
    "kyc": "pass",
    "kyc_timestamp": 1603378501285,
    "sanction_screening": "pass",
    "sanction_screening_timestamp": 1603378501285,
    "signed_timestamp": 1603378501286,
    "metadata": {},
    "platform_code": "ABC123",
    "participant_code": "XYZ456"
  }
}

Submits a customer to your platform.

Request body:

Parameter Description Type
request_id A universally unique identifier (UUID) for this request, optional
Note: To ensure idempotence, it is recommended to include this parameter
string
first_name The first name of the customer, required string
last_name The last name of the customer, required string
email Customer email address, required
Note: Zero Hash will validate that the email is a correctly formatted email, and that the value is unique per-platform
string
phone_number The phone number of the participant, conditionally required string
address_one First line for the customer's address, required
Note: PO Box addresses are not accepted
string
address_two First line for the customer's address, if applicable, optional string
city The city customer resides in, required string
state The state the customer resides in, required if country is "United States"
Note: must be one of the supported states
string
zip Zip code of the customer in the format <5digits> or <5digits>-<4digits>, e.g. 77777 or 77777-7777, required if country is "United States" string
country The country the customer resides in, required
Note: must be one of the supported countries
string
date_of_birth Date of birth of the customer in the format YYYY-MM-DD, required string
citizenship The citizenship of the participant, e.g. "United States", required string
tax_id The national ID of the participant, e.g. a social security number. Required if citizenship=United States. string
id_number_type The type of ID document provided, required if citizenship is not United States
Note: must be one of the supported ID types ID types
string
id_number The ID number for the customer, required if citizenship is not United States string
non_us_other_type This is required if you select non_us_other for the id_number_type - a freeform string to describe the ID type string
id_issuing_authority The issuing authority for the ID, if available, optional string
risk_rating The risk-rating associated with the customer, conditionally required for certain platforms string (low, medium, high)
kyc Whether the participant passed or failed KYC by vendor, required string (pass, fail)
kyc_timestamp The UNIX timestamp (in milliseconds) when KYC was passed, required timestamp
sanction_screening Whether the participant passed sanctions checks, required string (pass, fail)
sanction_screening_timestamp The UNIX timestamp (in milliseconds) when sanction screening was passed, required timestamp
idv Whether the participant passed or failed ID verification, optional string (pass, fail)
liveness_check Whether the participant passed or failed a liveness check, optional string (pass, fail)
signed_timestamp The UNIX timestamp (in milliseconds) when the Zero Hash Services Agreement was accepted by the participant timestamp
metadata Can be used to submit any additional unstructured metadata object

Additional fields in response:

Parameter Description Type
platform_code The unique identifier for the Platform onto which the customer has been created string
participant_code The Zero Hash identifier for the new customer
Note: this value is key to enable you to submit trades and check account balances for this customer
string

Possible Responses:

Status Code Description
200 OK The customer was successfully created. Note: the request is idempotent only IF therequest_id and payload is the same as previously submitted
400 Bad Request The request is invalid, OR the payload is the same as a previously submitted request, but the request_id is different, OR, the request_id is the same as a previously submitted request, but the payload is different

Supported Regions

Zero Hash operates in a wide range of supported regions. For more information, please contact us to learn more. Please refer to our disclosures page for more information on regional regulation. Specifically, you can see a list of disclosures pertaining to certain states in which Zero Hash has licensing here.

ID Types

Valid options are:

PATCH /participants/customers/:participantCode

const patchParticipantCustomer = () => {
  const body = {
    request_id: '7fbab305-2679-4279-808b-9b7a63a55c85',
    first_name: 'John',
    last_name: 'Smith',
    address_one: '1 Main St.',
    address_two: 'Suite 1000',
    country: 'United States',
    state: 'IL',
    city: 'Chicago',
    zip: '12345',
    email: 'email-example@mail.com',
    id_number_type: 'ssn',
    id_number: '123456789',
    platform_updated_at: 1603378501286
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'PATCH' + '/participants/customers/XXXXXX' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/customers/XXXXXX`,
    options
  )
}
resp = make_seed_request('PATCH', '/participants/customers/XXXXXX', {...})

Sample Request

{
  "request_id": "7fbab305-2679-4279-808b-9b7a63a55c85",
  "first_name": "John",
  "last_name": "Smith",
  "address_one": "1 Main St.",
  "address_two": "Suite 1000",
  "country": "United States",
  "state": "IL",
  "city": "Chicago",
  "zip": "12345",
  "email": "email-example@mail.com",
  "id_number_type": "ssn",
  "id_number": "123456789",
  "platform_updated_at": 1603378501286
}

Sample Response

{
  "message": {
    "first_name": "John",
    "last_name": "Smith",
    "address_one": "1 Main St.",
    "address_two": "Suite 1000",
    "country": "United States",
    "state": "IL",
    "city": "Chicago",
    "zip": "12345",
    "email": "email-example@mail.com",
    "date_of_birth": "1983-08-25",
    "id_number_type": "ssn",
    "id_number": "123456789",
    "non_us_other_type": "",
    "id_issuing_authority": "",
    "signed_timestamp": 1603378501287,
    "risk_rating": "",
    "platform_code": "ABC123",
    "participant_code": "XYZ456",
    "platform_updated_at": 1603378501286
  }
}

This endpoint enables you to update information that’s been validated with your customers. When making certain updates, groups of data must be sent together. If the data is not represented below, it’s not updatable. You can update more than one group of data at one time.

Request body:

Type of update Parameter Description Type
platform_updated_at The UNIX timestamp in milliseconds of when your customer updated their information with you and you approved that update. Only one timestamp should be sent per call (i.e. if you update name and address at the same time, there should be one timestamp, not one timestamp for name and one timestamp for address) number
Name (e.g. customer gets married and changes their last name)
first_name The first name of the customer, required string
last_name The last name of the customer, required string
Address (e.g. customer moves)
address_one First line for the customer's address, required
Note: PO Box addresses are not accepted
string
address_two First line for the customer's address, if applicable, optional string
country The country the customer resides in, required
Note: must be one of the supported countries
string
state The state the customer resides in, required if country is "United States"
Note: must be one of the supported states
string
city The city customer resides in, required string
zip Zip code of the customer in the format<5digits> or <5digits>-<4digits>, e.g. 77777 or 77777-7777, required if country is "United States" string
Email (e.g. customer changes from a work to a personal email)
email Customer email address, required
Note: Zero Hash will validate that the email is a correctly formatted email, and that the value is unique per-platform
string
Identification (e.g. customer updates their ID on file with you)
id_number_type The type of ID document provided, required
Note: must be one of the supported ID types
string
id_number The ID number of the customer, required string
Citizen records (only available where entries are currently blank)
citizenship If the participant does not have a defined citizenship, this can be added, one-time string
tax_id If the participant was created, but now requires a tax_id, this can be added, one-time string
Contact information
phone_number Mobile phone number of the participant string

Additional fields in response:

Parameter Description Type
platform_code The unique identifier for the Platform onto which the customer has been created string
participant_code The Zero Hash identifier for the new customer
Note: this value is key to enable you to submit trades and check account balances for this customer
string
platform_updated_at The timestamp of when a customer updated their information with your platform number

Possible Responses:

Status Code Description
200 OK The customer was successfully created. Note: the request is idempotent only IF therequest_id and payload is the same as previously submitted
400 Bad Request The request is invalid, OR the payload is the*same* as a previously submitted request, but the request_id is different, OR, the request_id is the same as a previously submitted request, but the payload is different

POST /participants/customers/:participantCode/lock

const postParticipantCustomerLock = () => {
  const body = {
    reason_code: "compliance_issue",
    notes: "confirmed fraud"
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/participants/customers/XXXXXX/lock' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/customers/XXXXXX/lock`,
    options
  )
}
resp = make_seed_request('POST', '/participants/customers/XXXXXX/lock', {...})

Sample Request

{
  "reason_code": "compliance_issue",
  "notes": "confirmed fraud"
}

Sample Response

OK

When platforms terminate a customer, they may alert Zero Hash through this endpoint. Hitting this endpoint will lock the user so the Zero Hash compliance team can conduct investigations.

Please note: Platforms cannot update the participant status further - once the participant is locked, the Zero Hash compliance team must take action and will potentially request supporting evidence from the platform.

If making a request for a participant who has been locked or disabled, platforms will receive an error message of Participant [participant_code] is not allowed to transact

Request body:

Parameter Description Type
reason_code compliance_issue or user_request, required string
notes Additional details on the lock, which can drastically speed up investigations on the Zero Hash side string

Possible Responses:

Status Code Description
200 OK The customer was successfully created. Note: the request is idempotent only IF therequest_id and payload is the same as previously submitted
400 Bad Request The request is invalid or failed

Custodian Relationship Types

Valid options are:

POST /participants/customers/minor

const postParticipantMinor = () => {
  const body = {
    first_name: 'John',
    last_name: 'Smith',
    email: 'test@example.com',
    address_one: '1 Main St.',
    address_two: 'Chicago',
    country: 'United States',
    city: 'Chicago',
    zip: '12345',
    state: 'IL',
    date_of_birth: '2018-09-02',
    id_number_type: 'ssn',
    id_number: '123456789',
    non_us_other_type: null,
    id_issuing_authority: null,
    utma_signed_timestamp: 1603378501286,
    custodian_participant_code: 'CAST01',
    custodian_relationship: 'parent',
    metadata: {}
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/participants/customers/minor' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/customers/minor`,
    options
  )
}
resp = make_seed_request('POST', '/participants/customers/minor', {})

Sample Request

{
  "first_name": "John",
  "last_name": "Smith",
  "email": "test@example.com",
  "address_one": "1 Main St.",
  "address_two": "Chicago",
  "country": "United States",
  "city": "Chicago",
  "zip": "12345",
  "state": "IL",
  "date_of_birth": "2018-09-02",
  "id_number_type": "ssn",
  "id_number": "123456789",
  "non_us_other_type": null,
  "id_issuing_authority": null,
  "utma_signed_timestamp": 1603378501286,
  "custodian_participant_code": "CAST01",
  "custodian_relationship": "parent",
  "metadata": {}
}

Sample Response

{
  "message": {
    "first_name": "string",
    "last_name": "string",
    "email": "user@example.com",
    "address_one": "string",
    "address_two": "string",
    "country": "string",
    "city": "string",
    "zip": "string",
    "state": "string",
    "date_of_birth": "string",
    "id_number_type": "ssn",
    "id_number": "string",
    "non_us_other_type": "string",
    "id_issuing_authority": "string",
    "utma_signed_timestamp": 0,
    "custodian_participant_code": "string",
    "participant_code": "string",
    "platform_code": "string",
    "custodian_relationship": "string",
    "metadata": {}
  }
}

Submits a minor and links it to a custodian. Used in the context of the UTMA product.

Request body:

Parameter Description Type
first_name The first name of the customer, required string
last_name The last name of the customer, required string
email Customer email address, required
Note: Zero Hash will validate that the email is a correctly formatted email, and that the value is unique per-platform
string
address_one First line for the customer's address, required
Note: PO Box addresses are not accepted
string
address_two First line for the customer's address, if applicable, optional string
city The city customer resides in, required string
state The state the customer resides in, required if country is "United States"
Note: must be one of the supported states
string
zip Zip code of the customer in the format <5digits> or <5digits>-<4digits>, e.g. 77777 or 77777-7777, required if country is "United States" string
country The country the customer resides in, required
Note: must be one of the supported countries
string
date_of_birth Date of birth of the customer in the format YYYY-MM-DD, required string
id_number_type The type of ID document provided, required
Note: must be one of the supported ID types
string
id_number The ID number for the customer, required string
non_us_other_type This is required if you select non_us_other for the id_number_type - a freeform string to describe the ID type string
id_issuing_authority The issuing authority for the ID, if available, optional string
utma_signed_timestamp The UNIX timestamp (in milliseconds) when the User Agreement UTMA Addendum was accepted by the custodian timestamp
custodian_participant_code The already-submitted participant code of the associated custodian object
custodian_relationship The type of custodian provided. if the field is filled, must be one of the supported custodian relationship string
metadata Can be used to submit any additional unstructed metadata object

Additional fields in response:

Parameter Description Type
platform_code The unique identifier for the Platform onto which the customer has been created string
participant_code The Zero Hash identifier for the new customer
Note: this value is key to enable you to submit trades and check account balances for this customer
string

Supported Regions

Zero Hash operates in a wide range of supported regions. For more information, please contact us to learn more. Please refer to our disclosures page for more information on regional regulation. Specifically, you can see a list of disclosures pertaining to certain states in which Zero Hash has licensing here.

ID Types

Valid options are:

POST /participants/documents

const postParticipantDocument = (filepath) => {
  const document = fs.readFileSync(filepath).toString('base64')

  const body = {
    document,
    mime: 'pdf',
    file_name: 'supporting_document.pdf',
    participant_code: 'ABC123'
  }

  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/participants/documents' + JSON.stringify(
    {})
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  const fileHash = crypto
    .createHash('sha256')
    .update(body.document)
    .digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase',
    'X-SCX-FILE-HASH': fileHash
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/documents`,
    options
  )
}
with open(filepath, 'rb') as document:
   resp = make_seed_request('POST', '/participants/documents', {
        'document': base64.b64encode(document.read()),
        'mime': 'pdf',
        'file_name': 'supporting_document.pdf',
        'participant_code': 'ABC123'
    })

Sample Request

{
  "document": "aGVsbG8gd29ybGQ=",
  "mime": "pdf",
  "file_name": "supporting_document.pdf",
  "participant_code": "ABC123"
}

Sample Response

{
  "message": {
    "state": "Success",
    "file_name": "supporting_document.pdf",
    "created_at": 1572899177383
  }
}

Submits a document on behalf of you or a customer if you operate a platform on Zero Hash. In order to Authenticate you will need to do the following:

Request body:

Parameter Description Type
document base 64 encoded file that you wish to upload (10mb limit) binary
mime The MIME type of the file you are uploading string
file_name The name of the document that you are uploading string
participant_code Your participant code, or the participant_code of the customer on behalf of whom you are uploading the document string

POST /participants/entity/new

const postEntity = () => {
  const body = {
    request_id: "98957700-c08c-4c4c-9c6b-dcc70d3da90c",
    platform_code:"PLAT01",
    entity_name:"Entity Name",
    legal_name:"Legal Name",
    contact_number:"15553765432",
    website:"www.example.com",
    date_established:"2000-01-15",
    entity_type:"llc",
    address_one:"1 Main St.",
    address_two:"Suite 1000",
    city:"Chicago",
    state_or_province:"IL",
    postal_code:"12345",
    country:"United States",
    tax_id:"883987654",
    id_issuing_authority:"United States",
    risk_rating:"low",
    risk_vendor:"passbase",
    sanction_screening:"pass",
    sanction_screening_timestamp:1677252628000,
    metadata:{},
    signed_timestamp:1677252629000,
    submitter_email:"example@zerohash.com",
    control_persons:[
      {
        name:"Joe Doe",
        email:"joe.doe@test.com",
        address_one:"1 South St.",
        address_two:"Suite 2000",
        city:"Chicago",
        state_or_province:"IL",
        postal_code:"12345",
        country:"United States",
        date_of_birth:"1979-01-30",
        citizenship:"United States",
        tax_id:"123456789",
        id_number_type:"us_passport",
        id_number:"332211200",
        id_issuing_authority:"United States",
        sanction_screening:"pass",
        sanction_screening_timestamp:1677252628000
      },
      {
        name:"Joe Doe Jr",
        email:"joedoejr@test.com",
        address_one:"1 South St.",
        address_two:"Suite 2000",
        city:"Chicago",
        state_or_province:"IL",
        postal_code:"12345",
        country:"United States",
        date_of_birth:"1979-01-30",
        citizenship:"United States",
        tax_id:"123456779",
        id_number_type:"us_passport",
        id_number:"332511100",
        id_issuing_authority:"United States",
        sanction_screening:"pass",
        sanction_screening_timestamp:1677252628000
      }
    ],
    beneficial_owners:[
      {
        name:"Jane Doe",
        beneficial_owner:2,
        email:"jane.doe@test.com",
        address_one:"1 North St.",
        address_two:"Suite 3000",
        city:"Chicago",
        state_or_province:"IL",
        postal_code:"12345",
        country:"United States",
        date_of_birth:"1980-01-30",
        citizenship:"United States",
        tax_id:"013345678",
        id_number_type:"us_drivers_license",
        id_number:"P11122223333",
        id_issuing_authority:"United States",
        sanction_screening:"pass",
        sanction_screening_timestamp:1677252628000
      },
      {
        name:"Jane Doe Jr",
        beneficial_owner:1,
        email:"janedoejr@test.com",
        address_one:"1 North St.",
        address_two:"Suite 3000",
        city:"Chicago",
        state_or_province:"IL",
        postal_code:"12345",
        country:"United States",
        date_of_birth:"1980-01-30",
        citizenship:"United States",
        tax_id:"012345578",
        id_number_type:"us_drivers_license",
        id_number:"P11122243333",
        id_issuing_authority:"United States",
        sanction_screening:"pass",
        sanction_screening_timestamp:1677252628000
      }
    ]
  }
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/participants/entity/new' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/entity/new`,
    options
  )
}
resp = make_seed_request('POST', '/participants/entity/new', {})

Sample Request

{
  "request_id": "98957700-c08c-4c4c-9c6b-dcc70d3da90c",
  "platform_code":"PLAT01",
  "entity_name":"Entity Name",
  "legal_name":"Legal Name",
  "contact_number":"15553765432",
  "website":"www.example.com",
  "date_established":"2000-01-15",
  "entity_type":"llc",
  "address_one":"1 Main St.",
  "address_two":"Suite 1000",
  "city":"Chicago",
  "state_or_province":"IL",
  "postal_code":"12345",
  "country":"United States",
  "tax_id":"883987654",
  "id_issuing_authority":"United States",
  "risk_rating":"low",
  "risk_vendor":"passbase",
  "sanction_screening":"pass",
  "sanction_screening_timestamp":1677252628000,
  "metadata":{

  },
  "signed_timestamp":1677252629000,
  "submitter_email":"example@zerohash.com",
  "control_persons":[
    {
      "name":"Joe Doe",
      "email":"joe.doe@test.com",
      "address_one":"1 South St.",
      "address_two":"Suite 2000",
      "city":"Chicago",
      "state_or_province":"IL",
      "postal_code":"12345",
      "country":"United States",
      "date_of_birth":"1979-01-30",
      "citizenship":"United States",
      "tax_id":"123456789",
      "id_number_type":"us_passport",
      "id_number":"332211200",
      "id_issuing_authority":"United States",
      "sanction_screening":"pass",
      "sanction_screening_timestamp":1677252628000
    },
    {
      "name":"Joe Doe Jr",
      "email":"joedoejr@test.com",
      "address_one":"1 South St.",
      "address_two":"Suite 2000",
      "city":"Chicago",
      "state_or_province":"IL",
      "postal_code":"12345",
      "country":"United States",
      "date_of_birth":"1979-01-30",
      "citizenship":"United States",
      "tax_id":"123456779",
      "id_number_type":"us_passport",
      "id_number":"332511100",
      "id_issuing_authority":"United States",
      "sanction_screening":"pass",
      "sanction_screening_timestamp":1677252628000
    }
  ],
  "beneficial_owners":[
    {
      "name":"Jane Doe",
      "beneficial_owner":2,
      "email":"jane.doe@test.com",
      "address_one":"1 North St.",
      "address_two":"Suite 3000",
      "city":"Chicago",
      "state_or_province":"IL",
      "postal_code":"12345",
      "country":"United States",
      "date_of_birth":"1980-01-30",
      "citizenship":"United States",
      "tax_id":"013345678",
      "id_number_type":"us_drivers_license",
      "id_number":"P11122223333",
      "id_issuing_authority":"United States",
      "sanction_screening":"pass",
      "sanction_screening_timestamp":1677252628000
    },
    {
      "name":"Jane Doe Jr",
      "beneficial_owner":1,
      "email":"janedoejr@test.com",
      "address_one":"1 North St.",
      "address_two":"Suite 3000",
      "city":"Chicago",
      "state_or_province":"IL",
      "postal_code":"12345",
      "country":"United States",
      "date_of_birth":"1980-01-30",
      "citizenship":"United States",
      "tax_id":"012345578",
      "id_number_type":"us_drivers_license",
      "id_number":"P11122243333",
      "id_issuing_authority":"United States",
      "sanction_screening":"pass",
      "sanction_screening_timestamp":1677252628000
    }
  ]
}

Sample Response

{
  "message": {
    "platform_code": "PLAT01",
    "participant_code": "PART01",
    "status": "submitted",
    "entity_name": "Entity Name",
    "legal_name": "Legal Name",
    "address_one": "1 Main St.",
    "address_two": "Suite 1000",
    "country": "United States",
    "state_or_province": "IL",
    "city": "Chicago",
    "postal_code": "12345",
    "date_established": "2000-01-15",
    "risk_rating": "low",
    "risk_vendor": "passbase",
    "entity_type": "llc",
    "metadata": {},
    "signed_timestamp": 1677252629000,
    "tax_id": "883987654",
    "contact_number": "15553765432",
    "website": "www.example.com",
    "id_issuing_authority": "United States",
    "sanction_screening": "pass",
    "sanction_screening_timestamp": 1677252628000,
    "submitter_email": "example@zerohash.com",
    "beneficial_owners": [
      {
        "user_code": "U-USERCO",
        "beneficial_owner": 0,
        "name": "Jane Doe",
        "email": "jane.doe@test.com",
        "address_one": "1 North St.",
        "address_two": "Suite 3000",
        "city": "Chicago",
        "state_or_province": "IL",
        "postal_code": "12345",
        "country": "United States",
        "date_of_birth": "1980-01-30",
        "citizenship": "United States",
        "tax_id": "013345678",
        "id_number_type": "us_drivers_license",
        "id_number": "P11122223333",
        "id_issuing_authority": "United States",
        "sanction_screening": "pass",
        "sanction_screening_timestamp": 1677252628000
      },
      {
        "user_code": "U-USERC1",
        "beneficial_owner": 0,
        "name": "Jane Doe Jr",
        "email": "janedoejr@test.com",
        "address_one": "1 North St.",
        "address_two": "Suite 3000",
        "city": "Chicago",
        "state_or_province": "IL",
        "postal_code": "12345",
        "country": "United States",
        "date_of_birth": "1980-01-30",
        "citizenship": "United States",
        "tax_id": "012345578",
        "id_number_type": "us_drivers_license",
        "id_number": "P11122243333",
        "id_issuing_authority": "United States",
        "sanction_screening": "pass",
        "sanction_screening_timestamp": 1677252628000
      }
    ],
    "control_persons": [
      {
        "user_code": "U-USERC2",
        "name": "Joe Doe",
        "email": "joe.doe@test.com",
        "address_one": "1 South St.",
        "address_two": "Suite 2000",
        "city": "Chicago",
        "state_or_province": "IL",
        "postal_code": "12345",
        "country": "United States",
        "date_of_birth": "1979-01-30",
        "citizenship": "United States",
        "tax_id": "123456789",
        "id_number_type": "us_passport",
        "id_number": "332211200",
        "id_issuing_authority": "United States",
        "sanction_screening": "pass",
        "sanction_screening_timestamp": 1677252628000
      },
      {
        "user_code": "U-USERC3",
        "name": "Joe Doe Jr",
        "email": "joedoejr@test.com",
        "address_one": "1 South St.",
        "address_two": "Suite 2000",
        "city": "Chicago",
        "state_or_province": "IL",
        "postal_code": "12345",
        "country": "United States",
        "date_of_birth": "1979-01-30",
        "citizenship": "United States",
        "tax_id": "123456779",
        "id_number_type": "us_passport",
        "id_number": "332511100",
        "id_issuing_authority": "United States",
        "sanction_screening": "pass",
        "sanction_screening_timestamp": 1677252628000
      }
    ]
  }
}

When posting new entities, platforms are also required to post documents. See POST /participants/entity/documents for information.

Request body:

Parameter Description Requirement Input
request_id A universally unique identifier (UUID) for this request
Note: To ensure idempotence, it is recommended to include this parameter
optional, but highly recommended string
platform_code Zero Hash platform code of the submitting platform required string
BUSINESS INFO
entity_name Name of the business required string
legal_name Registered legal name of the entity. This should not be a DBA or DBA equivalent required string
contact_number Phone number of the business required string
website Business website required string
date_established Date the business was established. This should reflect government registration for the entity required YYYY-MM-DD
entity_type The type of business that is onboarding, must be one of the supported Entity Types required string
address_one Address of the business, no P.O. Boxes required string
address_two Address of the registered business continued, no P.O. Boxes optional string
city City of the business required string
state_or_province State of the business required (for US address) string
postal_code Postal, or zip code, of the business, in the format <5digits> or <5digits>-<4digits>, e.g. 77777 or 77777-7777 required string
country Country of the business. Note: must be one of the supported countries required string
tax_id Tax identifier of the business (e.g. EIN in United States) required string
id_issuing_authority Country that issued the tax identifier (e.g. “United States”) required string
risk_rating Risk assessed by the platform’s vendor required low, medium, high
sanction_screening Result of the business sanctions screen required pass, fail
sanction_screening_timestamp The time the sanctions screen was done required UNIX timestamp in milliseconds
metadata Additional unstructured data optional object
signed_timestamp The time at which the business accepted Zero Hash services agreements required UNIX timestamp in milliseconds
CONTROL PERSON(S) submit as many as necessary, for each director, officer, member, or partner, etc.
name Full name of the control person required string
email Email address of control person required string
address_one Address of the control person, no P.O. Boxes required string
address_two Address of the control person continued, no P.O. Boxes optional string
city City of the control person required string
state_or_province State of the control person required (for US address) string
postal_code Postal, or zip code, of the control person, in the format <5digits> or <5digits>-<4digits>, e.g. 77777 or 77777-7777 required string
country Country of the control person required string
date_of_birth Birth date of the control person required YYYY-MM-DD
citizenship Citizenship of the control person (e.g. “United States”) required string
tax_id Tax identifier of the control person (e.g. 9-digit SSN in United States) conditionally required if citizenship = “United States” string
id_number_type Type of ID document provided. Note: must be one of the supported ID Number Types required string
id_number ID number of the ID document provided required string
id_issuing_authority Country that issued the ID, if available (e.g. “United States”) optional string
sanction_screening Result of the control person’s sanctions screen required pass, fail
sanction_screening_timestamp The time the control person’s sanctions screen was done required UNIX timestamp in milliseconds
BENEFICIAL OWNER(S) Individual(s) who controls ≥25%, submit as many as necessary. If no Beneficial Owner(s), this section can be omitted. Zero Hash only requires inclusion of BOs who hold ≥25%, but those who hold 10-24% can be disclosed for compliance due diligence at the platform’s discretion.
name Full name of the beneficial owner required string
beneficial_owner Designation of what percent of the business the person owns. Unknown = 0; Greater than or equal to 10% but less than 25% = 1; Greater than or equal to 25% = 2 required number
email Email address of beneficial owner required string
address_one Address of the beneficial owner, no P.O. Boxes required string
address_two Address of the beneficial owner continued, no P.O. Boxes optional string
city City of the beneficial owner required string
state_or_province State of the beneficial owner required string
postal_code Postal, or zip code, of the beneficial owner, in the format <5digits> or <5digits>-<4digits>, e.g. 77777 or 77777-7777 required string
country Country of the beneficial owner required string
date_of_birth Birth date of the beneficial owner required YYYY-MM-DD
citizenship Citizenship of the beneficial owner (e.g. “United States”) required string
tax_id Tax identifier of the beneficial owner (e.g. 9-digit SSN in United States) conditionally required if citizenship = “United States” string
id_number_type Type of ID document provided. Note: must be one of the supported ID Number Types required string
id_number ID number of the ID document provided required string
id_issuing_authority Country that issued the ID, if available (e.g. “United States”) optional string
sanction_screening Result of the beneficial owner’s sanctions screen required pass, fail 
sanction_screening_timestamp The time the beneficial owner’s sanctions screen was done required UNIX timestamp in milliseconds
SUBMITTER
submitter_email Email of the person who completed the KYC application and agreed to terms required string

Additional fields in response:

Parameter Description Type
participant_code The Zero Hash identifier for the new customer
Note: this value is key to enable you to submit trades and check account balances for this customer
string
status When a successful POST has occurred, the Zero Hash response includes the status of the business participant, which indicates whether or not the business participant can immediately make requests
  • submitted: entity must undergo manual review by Zero Hash
  • approved: entity is approved to begin making requests
user_code Zero Hash identifier for the Control Person(s) or Beneficial Owner(s). One code returned per person. string

Possible Responses:

Status Code Description
200 OK The participant was successfully created. See status to understand whether or not that participant can immediately transact.
400 Bad Request The request was invalid, or the request was missing required fields.

Supported Regions

Zero Hash operates in a wide range of supported regions. For more information, please contact us to learn more. Please refer to our disclosures page for more information on regional regulation. Specifically, you can see a list of disclosures pertaining to certain states in which Zero Hash has licensing here.

Entity Types

Valid options are:

ID Number Types

Valid options are:

POST /participants/entity/documents

const postEntityDocument = (filepath) => {
  const document = fs.readFileSync(filepath).toString('base64')

  const body = {
    document,
    mime: 'pdf',
    document_type: "proof_of_address",
    file_name: "proof_of_address.pdf",
    participant_code: 'ABC123'
  }

  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/participants/entity/documents' + JSON.stringify(
    {})
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  const fileHash = crypto
    .createHash('sha256')
    .update(body.document)
    .digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase',
    'X-SCX-FILE-HASH': fileHash
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(
    `https://api.zerohash.com/participants/entity/documents`,
    options
  )
}
with open(filepath, 'rb') as document:
   resp = make_seed_request('POST', '/participants/entity/documents', {
        'document': base64.b64encode(document.read()),
        'mime': 'pdf',
        "document_type": "proof_of_address",
        "file_name": "proof_of_address.pdf",
        'participant_code': 'ABC123'
    })

Sample Request - Business documents

{
  "document": "aGVsbG8gd29ybGQ=",
  "mime": "pdf",
  "document_type": "proof_of_address",
  "file_name": "proof_of_address.pdf",
  "participant_code": "ABC123"
}

Sample Response - Business documents

{
  "message": {
    "state": "Success",
    "file_name": "proof_of_address.pdf",
    "created_at": 1572899177383
  }
}

Sample Request - Control Person / Beneficial Owner documents

{
  "document": "aGVsbG8gd29ybGQ=",
  "mime": "jpg",
  "document_type": "us_passport"
  "file_name": "jane_doe_passport.jpg",
  "user_code": "XYZ789"
}

Sample Response - Control Person / Beneficial Owner documents

{
  "message": {
    "state": "Success",
    "file_name": "jane_doe_passport.jpg",
    "created_at": 1572899177383
  }
}

Posting a business participant requires that specific documentation is passed to Zero Hash. One document can be submitted per call. In order to Authenticate you will need to do the following:

Document requirements

Document requirements are validated and depend on the entity_type passed in POST /participants/entity/new.

Entity type Documents required (*if applicable)
Sole proprietorship
  • business_license*
  • business_name_filing_document*
  • business_name_filing_document*
  • proof_of_address
  • certificate_of_good_standing
  • valid ID types for Control Person(s) and Beneficial Owner(s)
Partnership
  • partnership_agreement
  • proof_of_address
  • certificate_of_good_standing
  • valid ID types for Control Person(s) and Beneficial Owner(s)
LLC
  • operating_agreement
  • articles_of_organization
  • certificate_of_organization
  • proof_of_address
  • certificate_of_good_standing
  • valid ID types for Control Person(s) and Beneficial Owner(s)
Corporation
  • certificate_of_incorporation
  • articles_of_incorporation
  • by_laws
  • proof_of_address
  • certificate_of_good_standing
  • valid ID types for Control Person(s) and Beneficial Owner(s)
Other If submitting a non-profit organization, Association/Organization agreement and/or by_laws, proof_of_address, proof_of_non_profit_status, + valid ID types for Control Person(s) are required.

Request body:

Parameter Description Requirement Input
document base 64 encoded file that you wish to upload (10mb limit) required binary
mime The MIME type of the file you are uploading required string
document_type The type of document provided.
Note: must be one of the supported Document types
required string
file_name The name of the document that you are uploading required string
participant_code OR user_code Zero Hash designated participant code of the business participant created in or the user code of the Control Person or Beneficial Owner required string

Document types

Valid options are:

Liquidity

GET /liquidity/rfq

const getQuote = () => {
  const body = '{}'
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/liquidity/rfq' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(`https://api.zerohash.com/liquidity/rfq?underlying=BTC&quoted_currency=USD&side=buy&quantity=1`, options)
}
accounts = make_seed_request('GET', '/liquidity/rfq', {})

Sample Response

{
  "request_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
  "participant_code": "CUST01",
  "quoted_currency": "USD",
  "side": "BUY",
  "quantity": "1",
  "price": "11430.90",
  "quote_id": "5cd07738b861c31e3bd61467BTC1Buy1568311644602",
  "expire_ts": 1568311649602,
  "account_group": "00SCXM",
  "account_label": "general",
  "obo_participant": {
    "participant_code": "20XRLH",
    "account_group": "WRD1K0",
    "account_label": "general"
  },
  "network_fee_notional": "1",
  "network_fee_quantity": "1",
  "main_quote_id": "c3a7e3a6-a911-43e8-b3bb-2b562c2d8c28",
  "total_notional": "11.00",
  "underlying": "ETH"
}

Returns a quote to buy or sell a certain asset, in return for another asset. See one-pager here for more details.

Query parameters include:

Response:

Parameter Description Type
request_id The identifier of the RFQ string
participant_code The identifier of the participant making the quote request string
quoted_currency The asset code for the quoted currency, e.g. USD string
side The participant side of the quote - buy or sell string
quantity The amount of the quoted currency string
price The cost per unit of underlying currency string
quote_id The identifier for the quote
Note: this is required to execute the quote
string
expire_ts Timestamp when the quote will expire timestamp
account_group The group that the account is a part of string
account_label The account label associated with the account string
obo_participant on behalf of participant is the details of the participant benefiting the trade if not the submitter object
network_fee_notional fee notional in the currency quoted on the RFQ string
network_fee_quantity fee quantity in the underlying asset string
main_quote_id the quote ID for the liquidity provider for the quote itself string
total_notional The calculation: (price * quantity) + (network_fee_notional * network_fee_quantity) string
underlying The asset code for the underlying currency, e.g. BTC string

POST /liquidity/execute

const executeQuote = (id: string) => {
  const body = '{ "quote_id":' + id + '}'
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/liquidity/execute' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/liquidity/execute`, options)
}
accounts = make_seed_request('POST', '/liquidity/execute', {"quote_id": id})

Sample Response

{
  "request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
  "quote": {
    "request_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
    "participant_code": "CUST01",
    "quoted_currency": "USD",
    "side": "BUY",
    "quantity": "1",
    "price": "11430.90",
    "quote_id": "5cd07738b861c31e3bd61467BTC1Buy1568311644602",
    "expire_ts": 1568311649602,
    "account_group": "GRP001",
    "account_label": "general",
    "obo_participant": {
        "participant_code": "20XRLH",
        "account_group": "WRD1K0",
        "account_label": "general"
     },
    "network_fee_notional": "1",
    "network_fee_quantity": "1",
    "total_notional": "2.00",
    "underlying": "BTC",
    "asset_cost_notional": "2.00"
  },
  "trade_id": "ba97133e-ab15-4c86-86c1-86671b8420bc",
  "status": "Completed",
  "ach_details": {
    "external_account_id": "5cd07738b861cuy1568311644602",
    "inbound_reference_id": "ref-id",
    "bank_fee": "1",
    "payment_amount": "10"
  }
}

Executes the quote identified by quote_id. The completed trade is submitted to settlement via the 00SCXM platform. Platforms may now use the funding_details sub-object to trigger Zero Hash to create an ACH transaction associated with a trade. Speak with Zero Hash support for more details.

Body parameters include:

Response:

Parameter Description Type
request_id The identifier of the RFQ. string
quote{} The quote object that was executed. quote
trade_id The unique identifier assigned to the trade, which is the same trade_id as found in a GET /trades request
Note: the quote_id will be saved as the client_trade_id.
string
status The status of the trade, e.g. Completed. string
payment_amount The final amount of the ACH transaction that will go out into the network. When executing a BUY this is the trade amount plus the bank_fee, for a SELL this is the trade amount minus the bank_fee. string

Convert and Withdraw

GET /convert_withdraw/rfq

const getQuote = () => {
  const body = '{}'
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/convert_withdraw/rfq' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.get(`https://api.zerohash.com/convert_withdraw/rfq?underlying=BTC&quoted_currency=USD&side=buy&quantity=1&withdrawal_address=address`, options)
}
accounts = make_seed_request('GET', '/convert_withdraw/rfq', {})

Sample Response

{
  "request_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
  "participant_code": "CUST01",
  "quoted_currency": "USD",
  "side": "BUY",
  "quantity": "1",
  "price": "11430.90",
  "quote_id": "5cd07738b861c31e3bd61467BTC1Buy1568311644602",
  "expire_ts": 1568311649602,
  "account_group": "00SCXM",
  "account_label": "general",
  "obo_participant": {
    "participant_code": "20XRLH",
    "account_group": "WRD1K0",
    "account_label": "general"
  },
  "network_fee_notional": "1",
  "network_fee_quantity": "1",
  "main_quote_id": "c3a7e3a6-a911-43e8-b3bb-2b562c2d8c28",
  "total_notional": "11.00",
  "underlying": "ETH",
  "asset_cost_notional": "20"
}

Returns a quote for the asset purchase amount and also the network fee associated with an eminent withdrawal.

Query parameters include:

Response:

Parameter Description Type
request_id The identifier of the RFQ string
participant_code The identifier of the participant making the quote request string
quoted_currency The asset code for the quoted currency, e.g. USD string
side The participant side of the quote - buy or sell string
quantity The amount of the quoted currency string
price The cost per unit of underlying currency string
quote_id The identifier for the quote
Note: this is required to execute the quote
string
expire_ts Timestamp when the quote will expire timestamp
account_group The group that the account is a part of string
account_label The account label associated with the account string
obo_participant on behalf of participant is the details of the participant benefiting the trade if not the submitter object
network_fee_notional fee notional in the currency quoted on the RFQ string
network_fee_quantity fee quantity in the underlying asset string
total_notional The calculation: (price * quantity) + (network_fee_notional * network_fee_quantity) string
underlying The asset code for the underlying currency, e.g. BTC string

POST /convert_withdraw/execute

const executeQuote = (id: string) => {
  const body = '{ "quote_id":' + id + '}'
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'GET' + '/convert_withdraw/execute' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/convert_withdraw/execute`, options)
}
accounts = make_seed_request('POST', '/convert_withdraw/execute', {"quote_id": id})

Sample Response

{
  "request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
  "quote": {
    "request_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
    "participant_code": "CUST01",
    "underlying_currency": "BTC",
    "quoted_currency": "USD",
    "side": "BUY",
    "quantity": "1",
    "price": "11430.90",
    "quote_id": "5cd07738b861c31e3bd61467BTC1Buy1568311644602",
    "expire_ts": 1568311649602,
    "transaction_timestamp": 1568311649600
  },
  "trade_id": "ba97133e-ab15-4c86-86c1-86671b8420bc",
  "status": "Completed"
}

Executes the quote identified by quote_id. The completed trade is submitted to settlement via the 00SCXM platform.

Body parameters include:

Response:

Parameter Description Type
request_id The identifier of the RFQ. string
quote The quote object that was executed. quote
trade_id The unique identifier assigned to the trade, which is the same trade_id as found in a GET /trades request
Note: the quote_id will be saved as the client_trade_id.
string
status The status of the trade, e.g. Completed. string

Payments

POST /payments/external_accounts

const createExternalAccount = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const body = {
    participant_code: 'ALI123',
    account_nickname: 'test1',
    account_number: '123456789',
    routing_number: '011401533',
    account_type: 'checking'
  }
  const payload = timestamp + 'POST' + '/payments/external_accounts' + JSON.stringify(body)
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/payments/external_accounts`, options)
}
body = {
  'participant_code': 'ALI123',
  'account_nickname': 'test1',
  'account_number': '123456789',
  'routing_number': '011401533',
  'account_type': 'checking'
}
accounts = make_seed_request('POST', '/payments/external_accounts', body)

Sample response

{
  "request_id": "0f68333e-2114-469d-b505-c850d776e063",
  "participant_code": "ALI123",
  "platform_code": "TES123",
  "account_nickname": "test1",
  "account_type": "checking",
  "external_account_id": "0f68333e-2114-469d-b505-c850d776e063",
  "created_at": "1975-08-19T23:15:30.000Z"
}

Creates a new external account object that is required when generating payment transactions.

Request body:

Parameter Description Type
participant_code The participant code of the Platform’s participant that the external account will be associated with. string
account_nickname The account nickname of the external account, i.e. “Primary Checking” string
account_number The full bank account number of the external account. string
routing_number The routing number of the bank where the external account is held. string
account_type Either “checking” or “savings” and indicates what type of account the external account is. string

Additional fields in response:

Parameter Description Type
external_account_id The unique identifier that Zero Hash generates to identify the external account. string

GET /payments/external_accounts

const getExternalAccounts = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const participantCodes = 'ALI123,TES123'
  const payload = `${timestamp}GET/payments/external_accounts?participants=${participantCodes}&page=1&size=20{}`
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    json: true
  }

  return request.get(`https://api.zerohash.com/payments/external_accounts?participants=ALI123,TES123&page=1&size=20`, options)
}
accounts = make_seed_request('GET', '/payments/external_accounts', {'participants': 'ALI123,TES123', 'page': 1, 'size': 20})

Sample response

{
  "message": [
    {
      "request_id": "0f68333e-2114-469d-b505-c850d776e063",
      "account_number": "123456789",
      "routing_number": "011401533",
      "participant_code": "ALI123",
      "platform_code": "TES123",
      "account_nickname": "test1",
      "account_type": "checking",
      "external_account_id": "0f68333e-2114-469d-b505-c850d776e063",
      "created_at": "1975-08-19T23:15:30.000Z",
      "updated_at": "1975-08-19T23:15:30.000Z"
    }
  ],
  "page": 1,
  "total_pages": 1,
  "page_size": 20,
  "count": 10
}

Used to get a list of external_accounts associated with a Platform’s participants.

Query parameters include:

Response:

Parameter Description Type
request_id The unique identifier generated by Zero Hash associated with the request. string
participant_code The participant code of the Platform’s participant that the external account will be associated with. string
account_nickname The account nickname of the external account, i.e. “Primary Checking” string
account_number The full bank account number of the external account. string
routing_number The routing number of the bank where the external account is held. string
account_type Accepts either “checking” or “savings” and indicates what type of account the external account is. string
external_account_id The unique identifier that Zero Hash generates to identify the external account. string

GET /payments/status

const getPaymentStatus = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const payload = `${timestamp}GET/payments/status{}`
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    json: true
  }

  return request.get(`https://api.zerohash.com/payments/status`, options)
}
status = make_seed_request('GET', '/payments/status', {})

Sample response

{
  "message": [
    {
      "transaction_id": "0f68333e-2114-469d-b505-c850d776e061",
      "participant_code": "ALI123",
      "amount": "12.01",
      "status": "posted",
      "transfer_type": "credit",
      "bank_transfer_id": "0f68333e-2114-469d-b505-c850d776e061",
      "created_at": "1975-08-19T23:15:30.000Z",
      "updated_at": "1975-08-19T23:15:30.000Z"
    }
  ],
  "page": 1,
  "total_pages": 1,
  "page_size": 200,
  "count": 10
}

This is an endpoint that a Platform can use to get the current status of payment transactions.

Query parameters include:

Response:

Parameter Description Type
transaction_id The unique identifier generated by Zero Hash for the transaction. string
trade_id If the payment is associated with a trade a trade_id will be present here otherwise it will be Null. string
participant_code The Platform’s participant that the payment is associated with. string
amount The final amount of the ACH transaction. string
status The current status of the payment transaction. Click here for more details on payment transaction statuses. string
transfer_type Indicates if the payment is a credit or a debit. string
bank_transfer_id A unique identifier that can be used to trace the transaction. string
created_at Timestamp when the payment was created. timestamp
updated_at Timestamp when the payment status was last changed. timestamp

GET /payments/history

const getPaymentHistory = () => {
  const timestamp = Math.round(Date.now() / 1000)
  const participantCode = 'ALI123'
  const payload = `${timestamp}GET/payments/history?participant=${participantCode}&page=1&size=20{}`
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    json: true
  }

  return request.get(`https://api.zerohash.com/payments/history?participant=ALI123&page=1&size=20`, options)
}
history = make_seed_request('GET', '/payments/history', {'participant': 'ALI123', 'page': 1, 'size': 20})

Sample response

{
  "message": [
    {
      "transaction_id": "0f68333e-2114-469d-b505-c850d776e061",
      "participant_code": "ALI123",
      "external_account_id": "0f68333e-2114-469d-b505-c850d776e063",
      "amount": "12.01",
      "bank_fee": "12.01",
      "ach_network": "ach",
      "transfer_type": "credit",
      "status_history": [
        {
          "status": "posted",
          "timestamp": "1975-08-19T23:15:30.000Z"
        }
      ],
      "trade_id": "0f34533e-2114-469d-b505-c850d776e061",
      "bank_transfer_id": "0f68333e-2114-469d-b505-c850d776e061",
      "created_at": "1975-08-19T23:15:30.000Z",
      "updated_at": "1975-08-19T23:15:30.000Z"
    }
  ],
  "page": 1,
  "total_pages": 1,
  "page_size": 20,
  "count": 10
}

Platforms can use this endpoint to get extended details about payment transactions which includes the full status change history.

Query parameters include:

Response:

Parameter Description Type
transaction_id The unique identifier generated by Zero Hash for the transaction. string
trade_id Is returned if the payment is associated with a trade otherwise will be Null. string
participant_code The Platform’s participant that the payment is associated with. string
external_account_id The external account that is associated with the payment. string
amount The final amount of the ACH transaction. string
bank_fee The fee amount that the Platform is wanting to charge the participant for the payment. string
ach_network The network that the payment is being transmitted. string
status_history The list of status objects, showing the history of status changes.
  • Status - the current status of the payment transaction. Click here for more details on payment transaction statuses
  • Timestamp - the timestamp that the status change occurred.
array
transfer_type Indicates if the payment is a credit or a debit. string
bank_transfer_id The unique identifier that can be used to trace the transaction. string
created_at The timestamp when the payment was created. timestamp
updated_at The timestamp when the payment status was last changed. timestamp

Payments Transaction Status

Status Description
submitted Payment transaction request has been successfully received by Zero Hash.
pending The payment has been created and is awaiting confirmation by the appropriate payment network that it has settled. Depending on the payment network the transaction can sit in a pending status for different periods of time.
posted The payment has been successfully sent to the receiving bank account.
failed The sending of the payment failed. This status would only occur after the transaction goes to a pending status.
reversed The payment was returned which can happen for different reasons such as inaccurate receiving bank details or the transaction was deemed unauthorized. This would only follow a transaction that has gone to a posted status.

Rewards

POST /rewards

const issueReward = (customer: string, asset: string, notional: string) => {
  const body = `{
    underlying: ${underlying},
    quoted_currency: 'USD',
    total: ${notional}
    participant_code: ${customer}
  }`
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/rewards' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/rewards`, options)
}
body = {
    'underlying': 'BTC',
    'quoted_currency': 'USD',
    'total': "500.00",
    'participant_code': 'CUST01'
}

accounts = make_seed_request('POST', '/rewards', body)

Sample Response

{
  "request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
  "quote": {
    "request_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
    "participant_code": "CUST01",
    "underlying_currency": "BTC",
    "quoted_currency": "USD",
    "side": "BUY",
    "quantity": "1",
    "price": "11430.90",
    "quote_id": "5cd07738b861c31e3bd61467BTC1Buy1568311644602",
    "expire_ts": 1568311649602,
    "obo_participant":{
      "participant_code":"20XRLH",
      "account_group":"WRD1K0",
      "account_label":"general"
    },
    "transaction_timestamp": 1568311649600
  },
  "trade_id": "ba97133e-ab15-4c86-86c1-86671b8420bc",
  "status": "Completed"
}

Executes a trade to issue a reward in a certain asset. See one-pager here for more details.

Optional request header include:

Parameter Description Type
X-REQUEST-ID Include a X-REQUEST-ID in the request header to ensure idempotent rewards requests UUID

Body parameters include:

Response:

Parameter Description Type
request_id The identifier of the RFQ string
quote The quote object that was executed quote
trade_id The unique identifier assigned to the trade, which is the same trade_id as found in a GET /trades request
Note: the quote_id will be saved as the client_trade_id
string
status The status of the trade, e.g. Completed string

Awards

These endpoints can be used to facilitate Awards payments as part of a promotional program, prize pool, bonus pool, giveaway, etc. See release notes here for more information

POST /awards/fund

Specify the amount, quoted currency, and asset that you intend to ultimately distribute to your customers via the POST /awards/distribute endpoint.

const fundAwards = (asset: string, notional: string) => {
  const body = `{
    asset: ${asset},
    total: ${notional}
  }`
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/awards' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/awards/fund`, options)
}
body = {
    'asset': 'BTC',
    'total': "500.00",
}

awards = make_seed_request('POST', '/awards/fund', body)

Sample Response

{
  "request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
  "quote": {
    "request_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3",
    "participant_code": "CUST01",
    "underlying_currency": "BTC",
    "quoted_currency": "USD",
    "side": "BUY",
    "quantity": "1",
    "price": "11430.90",
    "quote_id": "5cd07738b861c31e3bd61467BTC1Buy1568311644602",
    "expire_ts": 1568311649602,
    "transaction_timestamp": 1568311649600
  },
  "trade_id": "ba97133e-ab15-4c86-86c1-86671b8420bc",
  "status": "Completed"
}

Body parameters include:

Response:

Parameter Description Type
request_id The identifier of the RFQ string
quote The quote object that was executed quote
trade_id The unique identifier assigned to the trade, which is the same trade_id as found in a GET /trades request
Note: the quote_id will be saved as the client_trade_id
string
status The status of the trade, e.g. Completed string

POST /awards/distribute

Evenly distribute the purchased crypto among the specified customers.

const distributeAwards = (asset: string, quantity: string, customer_participant_codes: string[]) => {
  const body = `{
    asset: ${asset},
    quantity: ${quantity}
    participant_codes: ${customer_participant_codes}
  }`
  const timestamp = Math.round(Date.now() / 1000)
  const payload = timestamp + 'POST' + '/awards' + body
  const decodedSecret = Buffer.from(apiSecret, 'base64')
  const hmac = crypto.createHmac('sha256', decodedSecret)
  const signedPayload = hmac.update(payload).digest('base64')

  // SET HEADERS
  const headers = {
    'X-SCX-API-KEY': 'public_key',
    'X-SCX-SIGNED': signedPayload,
    'X-SCX-TIMESTAMP': timestamp,
    'X-SCX-PASSPHRASE': 'passphrase'
  }
  const options = {
    headers,
    body,
    json: true
  }

  return request.post(`https://api.zerohash.com/awards/distribute`, options)
}
body = {
    'asset': 'BTC',
    'quantity': ".001",
    'participant_codes': [
      'CUST01',
      'CUST02',
    ]
}

awards = make_seed_request('POST', '/awards/distribute', body)

Sample Response

{
  "request_id": "14f8ebb8-7530-4aa4-bef9-9d73d56313f3",
  "confirms": [
    {
      "participant_code": "CUST01",
      "trade_id": "ce819fe8-b1d7-43bb-961c-e09ede0988d3"
    },
    {
      "participant_code": "CUST02",
      "trade_id": "ba97133e-ab15-4c86-86c1-86671b8420bc"
    }
  ]
}

Body parameters include:

Response:

Parameter Description Type
request_id The identifier of the request string
confirms A list of participant_code plus trade identifiers for the executed trades confirm confirm

Market Data

GET /market_data/ohlcv

Sample Response

{
  "message": [
    {
      "time": 1683065100,
      "high": 28730.35,
      "low": 28710.94,
      "open": 28711.99,
      "underlying_volume": 7.682,
      "quoted_volume": 220637.37,
      "close": 28724.54,
      "average_transaction_price": 28721.34
    }
  ]
}

Query for the historical data of open, high, low, close, underlying_volume and quoted_volume.

The following query parameters are required:

Parameter Description Type
underlying First symbol in a pair string
quoted_currency Second symbol in a pair. Usually a fiat currency - USD, BRL, AUD, GBP or EUR string
time_frame Specifies the OHLCV intervals - minute, hourly or daily string
limit Limit to how much data will be returned, max 2000 number
data_end_date Pulls all available data until this date. Limit 2000 datapoints at a time. Use this to pull all available historical data by moving this date back. timestamp
all_data Applies only to the daily time frame. Pulls all available historical data boolean

Private Socket Feed

Overview

The private WebSocket feed provides real-time balance and price updates for streamlined processing.

Important considerations

A long-lived TCP connection such as the one used by the WebSocket can be subject to multiple issues, including but not limited to: network instabilities on client/server, timeouts, ISP, etc.. These issues are expected to happen at any point in time, thus it's fundamental to have a reconnection/resubscription mechanism in place, which you'll find samples for in the examples below.

Endpoints

Authentication

The same authentication mechanism used for the Web API applies to the WebSocket: all sent messages must be properly signed to ensure authenticity of the request.

import hashlib
import hmac
from base64 import b64decode, b64encode

def sign(api_key: str, method: str, route: str, json_body: str, timestamp: str) -> bytes:
    """
        Given a key and data, create and sign a payload.

        :param api_key: Key to sign the message with
        :param method: HTTP method
        :param route: Relative route.
        :param json_body: JSON as a string. Usually created via json.dumps(dict)
        :param timestamp: Unix Epoch time as a string
        :return: Base64 encoded digest
    """
    msg = bytes(timestamp + method + route + json_body, encoding='utf-8')
    hm = hmac.new(key=b64decode(api_key), msg=msg, digestmod=hashlib.sha256)
    return b64encode(hm.digest())
const crypto = require('crypto');

const sign = (body, secret) => {
  let ts = String(Math.round(Date.now() / 1000));
  let payload = ts + 'POST' + '/' + JSON.stringify(body);
  let decodedSecret = Buffer.from(secret, 'base64');
  let hmac = crypto.createHmac('sha256', decodedSecret);
  let signedPayload = hmac.update(payload).digest('base64');
};

Basic setup

The JS and Python examples provide basic functionality for handling outgoing and incoming messages as well as a basic reconnection/resubscription mechanism in case of unexpected network failures. These examples provide a baseline to build upon, be sure to modify them in order to accomodate it to your language, library, framework and system needs.

const WebSocket = require('ws');
const crypto = require('crypto');

// NB: THESE CREDENTIALS SHOULD NOT BE STORED IN PLAINTEXT
// Keys here are kept in plaintext for the purposes of demonstration
// We encourage you to encrypt your keys and decrypt them only when being used
const KEY = '...';
const SECRET = '...';
const PASSPHRASE = '...';

const sign = (body, secret) => {
  let ts = String(Math.round(Date.now() / 1000));
  let payload = ts + 'POST' + '/' + JSON.stringify(body);
  let decodedSecret = Buffer.from(secret, 'base64');
  let hmac = crypto.createHmac('sha256', decodedSecret);
  let signedPayload = hmac.update(payload).digest('base64');
};

const sendWebsocketMessage = (client, type, body, secret, key, phrase) => {
  const ts = String(Math.round(Date.now() / 1000));
  const payload = ts + 'POST' + '/' + JSON.stringify(body);
  const decodedSecret = Buffer.from(secret, 'base64');
  const hmac = crypto.createHmac('sha256', decodedSecret);
  const signedPayload = hmac.update(payload).digest('base64');

  let data = JSON.stringify({
    messageType: type,
    body: body,
    key: key,
    passphrase: phrase,
    timestamp: ts,
    signature: signedPayload
  });

  console.log('sending message:', data);

  client.send(data);
};

const ws = new WebSocket(`wss://ws.cert.zerohash.com`);

ws.on('open', () => {
  sendWebsocketMessage(ws, 'subscribe', { filter: {} }, SECRET, KEY, PASSPHRASE);
});

ws.on('message', (data) => {
  console.log('received message:', JSON.parse(data));
});

ws.on('error', (data) => {
  console.log('unexpected error:', data);
});

setInterval(() => {
  sendWebsocketMessage(ws, 'ping', {}, SECRET, KEY, PASSPHRASE);
}, 10000);
# Even after removing type annotations, the below code works with Python 3.4+ only.
# For ease of use, Python 3.6+ is recommended if using websockets.

import asyncio
import hashlib
import hmac
import json
from asyncio.exceptions import IncompleteReadError
from base64 import b64decode, b64encode
from datetime import datetime
from logging import getLogger

from websockets.client import connect
from websockets.exceptions import ConnectionClosed, ConnectionClosedError

logger = getLogger(__name__)

# NB: THESE CREDENTIALS SHOULD NOT BE STORED IN PLAINTEXT
# Keys here are kept in plaintext for the purposes of demonstration
# We encourage you to encrypt your keys and decrypt them only when being used
WS_URL = "wss://ws.cert.zerohash.com"
API_PUBLIC_KEY = "..."
API_PRIVATE_KEY = "..."
API_PASSPHRASE = "..."


class Feed:
    async def connect_private(self):
        """Connect to the private websocket endpoint that requires authentication."""
        async for conn in connect(WS_URL):
            t = str(int(datetime.now().timestamp()))
            sig = self._sign(API_PRIVATE_KEY, "POST", "/", json.dumps({"filter": {}}, separators=(",", ":")), t)
            msg = json.dumps(
                {
                    "messageType": "subscribe",
                    "body": {"filter": {}},
                    "key": API_PUBLIC_KEY,
                    "passphrase": API_PASSPHRASE,
                    "timestamp": t,
                    "signature": sig.decode("utf-8"),
                },
                indent=2,
            )

            try:
                print("sending message:", msg)
                await conn.send(msg)
                while True:
                    self._message_handler(await conn.recv())
            # Be sure to handle other relevant network issues/exception provided by your WebSocket library of choice
            except ConnectionClosed or ConnectionClosedError or IncompleteReadError as e:
                print("Network issue encountered, backing off and reconnecting. Details: ", e)
                asyncio.sleep(5)
                continue


    def _message_handler(self, msg: str):
        """Simple message handling for data received from the WebSocket."""
        try:
            msg = json.loads(msg)
        except json.JSONDecodeError:
            logger.error("Error loading JSON message from server: {}".format(msg))
            return
        if "message" in msg:
            logger.info(msg["message"])
            return
        print("received message:", msg)


    def _sign(self, api_key: str, method: str, route: str, json_body: str, timestamp: str) -> bytes:
        msg = bytes(timestamp + method + route + json_body, encoding="utf-8")
        hm = hmac.new(key=b64decode(api_key), msg=msg, digestmod=hashlib.sha256)
        return b64encode(hm.digest())


loop = asyncio.get_event_loop()
loop.run_until_complete(Feed().connect_private())

Balances

The balance feed provides real-time updates when the balance is updated for any accounts that match the subscription filters.

Initial Subscription

In order to subscribe to the balance feed, a message of type subscribe must be sent.

Parameter Description Type
body{} An object used to restrict what is returned in the subscription. This must be included but can be empty. object
messageType Subscription message type - subscribe string
topic Topic to subscribe to - balances for the balance feed. Can be omitted. string
useMultiChainAssetFormat Include chain in asset names, e.g. AAVE.ETH vs. AAVE for the balance feed. Can be omitted. Default is false boolean
key Your public key string
passphrase Your passphrase string
timestamp Time in seconds since Unix Epoch string
signature your hmac signature string

Subscription Filters

Optional filters you can include within the body to restrict which balance updates will be sent by the WebSocket:

Parameter Description Type
filter{} A filter object used to specify account characteristics object

The filter{} object can include:

Parameter Description Type
account_owner The participant code for the specific participant you want updates for string
account_group The group that you want updates for string
account_type The type that you want updates for - available, collateral, payable, receivable or collateral_deficiency string
asset The asset code you would like updates for string

Subscription Response

Subscription Response

{
    "messageType": "initial-balance",
    "body": [
        {
            "account_id": "12345",
            "participant_code": "ABC123",
            "account_group": "XYZ456",
            "account_label": "general",
            "account_type": "available",
            "asset": "BTC",
            "balance": "1.00",
            "run_id": 1,
            "run_type": "unknown"
        }
    ]
}

Upon successfully subscribing you will receive an initial-balance message which includes a snapshot of all current account balances that meet your subscription criteria.

Parameter Description Type
account_id Unique ID of the specific account string
participant_code The code of the participant that owns the account string
account_group The group that the account is a part of string
account_label The account label to filter the response by string
account_type available, collateral, payable, receivable or collateral_deficiency string
asset The asset code for the specific account, e.g. USD string
balance The balance in the account string
run_id A unique ID for the particular run int
run_type The type of run string

Balance Update

Sample Response

{
    "messageType": "balance-updated",
    "body": {
        "participant_code": "ABC123",
        "account_group": "XYZ456",
        "account_label": "general",
        "account_type": "available",
        "asset": "BTC",
        "balance": "1.01",
        "run_id": 1,
        "run_type": "settlement",
        "movements": [
            {
                "movement_timestamp": "2021-11-04T02:50:16.202915702Z",
                "movement_id": "EFG456",
                "movement_type": "final_settlement",
                "deposit_reference_id": "deposit 123",
                "change": "123.123",
                "source": "deposit 123 sending address",
                "received_address": "deposit 123 received address"
            }
        ],
        "run_timestamp": "2021-11-04T02:51:16.202911633Z"
    }
}

After receiving the initial-balance message, you will be sent incremental balance-updated messages, which show any balance changes to accounts that meet your subscription criteria.

Parameter Description Type
participant_code The code of the participant that owns the account string
account_group The group that the account is a part of string
account_label The account label to filter the response by string
account_type available, collateral, payable, receivable or collateral_deficiency string
asset The asset code for the specific account, e.g. USD string
balance Updated balance value string
run_id A unique ID for the particular run string
run_type The type of run string
run_timestamp Timestamp when the account balance was updated timestamp
movements[] An array of movements related to the specific account update
Refer to the GET /accounts/:account_id/movements section for field definitions
array

Prices

The price feed provides real-time Bid/Ask price levels of up to a depth of 10 for the available symbols.

Listing available symbols

The symbols available for subscription can be fetched by sending a message of type info and with the topic set to available-symbols.

{
  "messageType": "info",
  "topic": "available-symbols",
  "key": "API_PUBLIC_KEY",
  "passphrase": "PASSPHRASE",
  "timestamp": "TIMESTAMP",
  "signature": "SIGNATURE"
}

Available symbols response

{
  "messageType": "info",
  "topic": "available-symbols",
  "body": {
    "message": [
      "BTC/USD",
      "ETH/USD",
      "LTC/USD",
      ...
    ]
  }
}

Subscribing to a Symbol

In order to subscribe to the price feed, a message of type subscribe must be sent.

{
  "messageType": "subscribe",
  "topic": "prices",
  "body": {
    "filter": {
      "symbol": "BTC/USD"
    }
  },
  "key": "API_PUBLIC_KEY",
  "passphrase": "PASSPHRASE",
  "timestamp": "TIMESTAMP",
  "signature": "SIGNATURE"
}
Parameter Description Type
body{} An object used to filter which symbol will be subscribed to. This is a required field for the price feed. object
messageType Subscription message type - subscribe string
topic Topic to subscribe to - prices for the price feed string
key Your public key string
passphrase Your passphrase string
timestamp Time in seconds since Unix Epoch string
signature your hmac signature string

Subscription response

{
  "body": "successfully subscribed to the BTC/USD feed",
  "messageType": "subscribe"
}

Price update

After successfully subscribing to a symbol, you will be sent price-updated messages whenever the price is updated.

Parameter Description Type
bid_levels[] Array of Bid price levels (up to a depth of 10) string
ask_levels[] Array of Ask price levels (up to a depth of 10) string
symbol The symbol which was subscribed to string
messageType Price update message type - price-update string

The price level object comprises these fields:

Parameter Description Type
price The level price string
quantity The level quantity string
side The level side - buy or sell string
{
  "messageType": "price-update",
  "body": {
    "symbol": "BTC/USD",
    "bid_levels": [
      {
        "price": "42260.4677",
        "quantity": "0.59",
        "side": "buy"
      },
      {
        "price": "42255.445175",
        "quantity": "1.77",
        "side": "buy"
      },
      {
        "price": "42251.475275",
        "quantity": "3.54",
        "side": "buy"
      },
      {
        "price": "42245.941475",
        "quantity": "7.09",
        "side": "buy"
      }
    ],
    "ask_levels": [
      {
        "price": "42317.16195",
        "quantity": "0.59",
        "side": "sell"
      },
      {
        "price": "42320.83275",
        "quantity": "1.77",
        "side": "sell"
      },
      {
        "price": "42324.872625",
        "quantity": "3.54",
        "side": "sell"
      },
      {
        "price": "42330.139425",
        "quantity": "7.09",
        "side": "sell"
      }
    ]
  }
}

Maintaining Subscription

Once subscribed to any of the above feeds, a ping message must be sent every 20 seconds to keep the subscription active; otherwise, the connection will be closed.

Ping Message

{
  "messageType": "ping",
  "key": "API_PUBLIC_KEY",
  "passphrase": "PASSPHRASE",
  "timestamp": "TIMESTAMP",
  "signature": "SIGNATURE"
}