zerocap-api
Python SDK for the Zerocap DMA API: ZerocapRestClient places and queries
orders, requests quotes and reads balances, transfers and wallets; ZerocapWebsocketClient streams prices and
order and trade updates. Requires Python 3.8 or later.
pip install zerocap-api
API keys are issued by Zerocap; contact Zerocap to register. Both clients take env='sandbox' (for testing) or
env='prod' and sign every request for you. The full API reference is at https://docs.zerocap.com/reference.
Contents
- REST API
- Websocket
- Changelog
REST API
import time
from zerocap_api import ZerocapRestClient
# API key and secret are required, please contact zerocap to register.
# Environments: 'prod' and 'sandbox' (any other value raises ValueError).
api_key = "***"
api_secret = "***"
client = ZerocapRestClient(api_key, api_secret, env='sandbox')
The client adds the authentication headers itself. The raw-request examples below show them for reference:
api-key, timestamp (integer Unix seconds) and signature (lowercase hex HMAC-SHA256 of the timestamp
string, keyed with your API secret).
1. Create an order
result = client.create_order(
symbol='USDT/AUD',
side='buy',
type='limit',
amount='100',
price='1000',
)
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| symbol | true | string | Instrument | USDT/AUD |
| side | true | string | Side | buy sell |
| type | true | string | Type | limit |
| amount | true | string | Quantity | |
| price | true | string | Price | |
| client_order_id | false | string | client_order_id |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
data =
{
"symbol": "USDT/AUD",
"side": "buy",
"type": "limit",
"amount": "1000",
"price": "1000",
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| id | true | string | Transaction ID | |
| timestamp | true | long | Time | |
| last_trade_timestamp | true | long | Time | |
| status | true | string | Status | |
| type | true | string | Type | |
| time_in_force | true | string | time_in_force | |
| side | true | string | Side | |
| price | true | float | Price | |
| average | true | float | average | |
| amount | true | float | Quantity | |
| filled | true | float | filled | |
| remaining | true | float | remaining | |
| cost | true | float | cost | |
| fee | true | float | fee | |
| error_message | true | string | error_message | |
| trades | true | list | trades | |
| client_order_id | true | string | client_order_id |
Response example:
{
"id": "d8dabfbd-e541-4262-b6c2-9f841ef220f6",
"timestamp": 1692346145000,
"last_trade_timestamp": 1692346145000,
"status": "closed",
"symbol": "USDT/AUD",
"type": "limit",
"time_in_force": "FOK",
"side": "sell",
"price": 1,
"average": 1.48249,
"amount": 500,
"filled": 500,
"remaining": 0,
"cost": 741.245,
"fee": 0,
"error_message": "",
"client_order_id": "",
"trades": [
{
"id": "e86fcf94-88e6-46d8-8cc6-e06891eab6cf",
"timestamp": 1692346145000,
"symbol": "USDT/AUD",
"order": "d8dabfbd-e541-4262-b6c2-9f841ef220f6",
"type": "limit",
"side": "sell",
"taker_or_maker": "taker",
"price": 1.48249,
"amount": 500,
"cost": 741.245,
"fee": 0
}
]
}
2. Fetch an order
result = client.fetch_order(
id='',
)
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| id | true | string | Transaction ID |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
data =
{
"id": "d8dabfbd-e541-4262-b6c2-9f841ef220f6",
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| id | true | string | Transaction ID | |
| timestamp | true | long | Time | |
| last_trade_timestamp | true | long | Time | |
| status | true | string | Status | |
| type | true | string | Type | |
| time_in_force | true | string | time_in_force | |
| side | true | string | Side | |
| price | true | float | Price | |
| average | true | float | average | |
| amount | true | float | Quantity | |
| filled | true | float | filled | |
| remaining | true | float | remaining | |
| cost | true | float | cost | |
| fee | true | float | fee | |
| error_message | true | string | error_message | |
| trades | true | list | trades | |
| client_order_id | true | string | client_order_id |
Response example:
{
"id": "d8dabfbd-e541-4262-b6c2-9f841ef220f6",
"timestamp": 1692346145000,
"last_trade_timestamp": 1692346145000,
"status": "closed",
"symbol": "USDT/AUD",
"type": "limit",
"time_in_force": "FOK",
"side": "sell",
"price": 1,
"average": 1.48249,
"amount": 500,
"filled": 500,
"remaining": 0,
"cost": 741.245,
"fee": 0,
"error_message": "",
"trades": [
{
"id": "e86fcf94-88e6-46d8-8cc6-e06891eab6cf",
"timestamp": 1692346145000,
"symbol": "USDT/AUD",
"order": "d8dabfbd-e541-4262-b6c2-9f841ef220f6",
"type": "limit",
"side": "sell",
"taker_or_maker": "taker",
"price": 1,
"amount": 500,
"cost": 741.245,
"fee": 0
}
]
}
3. Fetch orders
result = client.fetch_orders(
symbol='USDT/AUD',
end_datetime=int(time.time() * 1000),
start_datetime=int(time.time() * 1000 - 10*86400*1000),
limit=10,
)
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| symbol | false | string | symbol | |
| start_datetime | false | int | Start time, Unix milliseconds (inclusive) | |
| end_datetime | false | int | End time, Unix milliseconds (exclusive) | |
| page | false | int | Page number, starting from 1 (default 1) | |
| limit | false | int | Orders per page (default and maximum 500) | |
| ids | false | string | Transaction ids(null character string or id1,id2...) | |
| status | false | string | status | |
| sort_order | false | string | sort_order | |
| order_type | false | string | order_type | |
| side | false | string | side |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
data =
{
"symbol": "USDT/AUD",
"start_datetime": 0,
"end_datetime": 0,
"page": 1,
"limit": 500,
"ids": "",
"status": "",
"sort_order": "",
"order_type": "",
"side": "",
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| id | true | string | Transaction ID | |
| timestamp | true | long | timestamp | |
| last_trade_timestamp | true | long | last_trade_timestamp | |
| status | true | string | status | |
| symbol | true | string | symbol | |
| type | true | string | type | |
| time_in_force | true | string | time_in_force | |
| side | true | string | side | |
| price | true | float | price | |
| average | true | float | average | |
| amount | true | float | amount | |
| filled | true | float | filled | |
| remaining | true | float | remaining | |
| cost | true | float | cost | |
| fee | true | float | fee | |
| error_message | true | string | fee | |
| trades | true | list | trades | |
| total | true | int | total | |
| page | true | int | page | |
| client_order_id | true | string | client_order_id |
Response example:
{
"order_list": [
{
"id": "e1af8ae0-3247-4755-87ad-f683fed3aff5",
"timestamp": 1690797504000,
"last_trade_timestamp": 1690797504000,
"status": "closed",
"symbol": "USDT/AUD",
"type": "limit",
"time_in_force": "FOK",
"side": "buy",
"price": 21.1,
"average": 2.98442,
"amount": 101,
"filled": 101,
"remaining": 0,
"cost": 301.426,
"fee": 0,
"error_message": "",
"client_order_id": "",
"trades": [
{
"id": "e1b3329c-4fc3-455a-82ed-ab5497b286cc",
"timestamp": 1690797504000,
"symbol": "USDT/AUD",
"order": "e1af8ae0-3247-4755-87ad-f683fed3aff5",
"type": "limit",
"side": "buy",
"taker_or_maker": "taker",
"price": 21.1,
"amount": 101,
"cost": 301.426,
"fee": 0
}
]
}
],
"status": "success",
"total": 14087,
"page": 1
}
4. Request for quote
result = client.request_for_quote(
symbol='USDT/AUD',
side='buy',
amount='100',
client_order_id='',
)
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| symbol | true | string | Symbol | USDT/AUD |
| side | true | string | Side | buy sell |
| amount | true | string | Amount | |
| client_order_id | false | string | Client Order ID |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
data =
{
"symbol": "USDT/AUD",
"side": "buy",
"amount": "100",
"client_order_id": ""
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| rfq_id | true | string | RFQ ID | |
| client_order_id | true | string | Client Order ID | |
| amount | true | float | Amount | |
| side | true | string | Side | |
| symbol | true | string | Symbol | |
| price | true | float | price | |
| created | true | string | Side |
Response example:
{
"rfq_id": "3ec2f335-1995-4c59-9d3a-8e3a4d048d23",
"client_order_id": "",
"amount": 100.0,
"side": "buy",
"symbol": "USDT/AUD",
"price": 1.4882,
"created": "2024-01-15T02:49:17.658142Z"
}
5. Get instruments
result = client.get_instruments()
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| name | true | string | Name | |
| type | true | string | Type | |
| is_tradable | true | bool | Is Ttradable | |
| quantity_precision | true | float | Quantity Precision | |
| max_quantity | true | float | Max Quantity | |
| min_quantity | true | float | Min Quantity | |
| price_precision | true | float | Price Precision |
Response example:
{
"status": "successful",
"instruments": [
{
"name": "USDT/AUD",
"type": "SPOT",
"is_tradable": false,
"quantity_precision": 2.0,
"max_quantity": 50000.0,
"min_quantity": 1.0,
"price_precision": 4.0
}
]
}
6. Get balances
result = client.get_balances()
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| status | true | string | Request status | |
| datetime | true | string | Format time | |
| timestamp | true | int | Millisecond timestamp |
Response example:
{
"status": "successful",
"datetime": "2024-01-16T05:21:38Z",
"timestamp": 1705382498277,
"BTC": {"custody": {"free": 100, "total": 100, "used": 0}},
"AUD": {
"DiscountNote": {"free": 1080, "total": 1080, "used": 0},
"YieldEntryNotes": {"free": 3, "total": 3, "used": 0},
"custody": {"free": 3092.07032787879, "total": 3092.07032787879, "used": 0},
"prime": {"free": 3024064.624523521, "total": 3024064.624523521, "used": 0},
"prime_locked": {"free": 103.107987, "total": 103.107987, "used": 0},
},
"custody": {
"CAD": {"free": 98111.56, "total": 98111.56, "used": 0},
"ETH": {"free": 0, "total": 0, "used": 0},
},
"prime": {
"AUD": {"free": 3024064.624523521, "total": 3024064.624523521, "used": 0},
"BTC": {"free": 10.387466098753459, "total": 10.387466098753459, "used": 0},
},
"prime_locked": {
"AUD": {"free": 103.107987, "total": 103.107987, "used": 0},
"USDT": {"free": 12609.60579, "total": 12609.60579, "used": 0},
},
"savings": {
"BTC": {"free": 0.1003151580555734, "total": 0.1003151580555734, "used": 0}
},
"staking": {"DIVI": {"free": 300, "total": 300, "used": 0}},
"term_3M": {
"USDT_ETH_TEST3_EA4E": {
"free": 0.9939347875558201,
"total": 0.9939347875558201,
"used": 0,
}
},
"term_6M": {
"USDT_TRX_TEST4": {
"free": 9.80542196309589,
"total": 9.80542196309589,
"used": 0,
}
},
"unlock": {"BTC": {"free": 2.6246, "total": 2.6246, "used": 0}},
}
7. Get transfers
result = client.get_transfers(start_datetime=1706767455959,
end_datetime=1706770184310,
asset_id="ETH,AUD",
type="external_deposit,external_withdrawal",
page=1,
limit=20,
sort_order="desc")
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| start_datetime | false | int | Start Datetime | |
| end_datetime | false | int | End Datetime | |
| asset_id | false | string | Asset Id | |
| type | false | string | Type | external_deposit,external_withdrawal,yield_deposit,create_term_yield,settled_term_yield, trading_transfer,trading_settlement,yield_interest,yield_withdrawal |
| page | false | int | Page | |
| limit | false | int | Limit | |
| sort_order | false | string | Sort Order | desc, asc |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
data = {
"start_datetime": 1706767455959,
"end_datetime": 1706770184310,
"asset_id": "ETH,AUD",
"type": "external_deposit,external_withdrawal",
"page": 1,
"limit": 20,
"sort_order": "desc"
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| status | true | string | Interface request status. | |
| total | true | int | The total number of matching data. | |
| asset_id | true | string | Asset ID | |
| amount | true | float | Amount | |
| type | true | string | Type | |
| from_account_type | true | string | From Account Type | |
| to_account_type | true | string | To Account Type | |
| amount_usd | true | float | Amount USD | |
| interest_earned | true | string | Interest Earned | |
| tx_hash | true | string | Tx Hash | |
| source_address | true | string | Source Address | |
| destination_address | true | string | Destination Address | |
| tx_id | true | string | Tx ID | |
| fee | true | float | Fee | |
| fee_currency | true | string | Fee Currency | |
| name_reference | true | string | Name Reference | |
| bank_account | true | string | Bank Account | |
| comment | true | string | Comment | |
| status | true | string | Status | |
| created_at | true | long | Created At (milliseconds) |
Response example:
{
"status": "successful",
"total": 78,
"user_id": "",
"fiat_transactions": [
{
"user_id": "",
"asset_id": "AUD",
"amount": 1.22,
"type": "",
"from_account_type": "",
"to_account_type": "",
"amount_usd": 0.8004786,
"note": "",
"source_address": "",
"destination_address": "",
"tx_id": "a7ff3ee8-d62e-413d-8bf1-1e1305604883auto_sweep",
"fee": 0.0,
"fee_currency": "",
"comment": "",
"status": "COMPLETED",
"created_at": 1702267616000
},
],
"crypto_transactions": [
{
"user_id": "",
"asset_id": "AUD",
"amount": 1.22,
"type": "",
"from_account_type": "",
"to_account_type": "",
"amount_usd": 0.8004786,
"interest_earned": 0.0,
"note": "",
"tx_hash": "",
"source_address": "",
"destination_address": "",
"tx_id": "a7ff3ee8-d62e-413d-8bf1-1e1305604883auto_sweep",
"fee": 0.0,
"fee_currency": "",
"comment": "",
"status": "COMPLETED",
"created_at": 1702267616000
},
]
}
8. Get time
result = client.get_time()
Public endpoint: no parameters and no authentication headers (the client sends none). Use it to check your
clock before signing, since requests with a timestamp more than 30 s off are rejected with 408.
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| server_time | true | string | Server time, Unix seconds |
Response example:
{
"server_time": "1709654622"
}
9. Get risk
result = client.get_risk()
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
headers = {
'api-key': api_key,
'signature': signature,
'Content-Type': 'application/json',
'timestamp': str(timestamp),
}
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| max_risk_limit | true | string | Max Risk Limit | |
| risk_exposure | true | string | Risk Exposure | |
| equity | true | string | Equity |
Response example:
{
"max_risk_limit": "100000",
"risk_exposure": "0",
"equity": "17048.35"
}
10. Request for firm quote
result = client.request_for_firm_quote(symbol='USDT/AUD', side='buy', amount='100', currency='', client_order_id='')
Returns a fixed-price quote with a quote_id (plus client_order_id, amount, side, symbol, price, created, currency, base_amount, quote_amount and expires_at, the expiry time in milliseconds). Pass the quote_id to accept_quote before expires_at.
11. Accept quote
result = client.accept_quote(quote_id='<quote_id from request_for_firm_quote>', client_order_id='')
Accepts a firm quote and creates a FOK order.
12. Get external wallets
result = client.get_external_wallets()
Returns external_wallets: a list of external_wallet_id, name, address, label, status, asset, network, asset_id.
13. Initiate withdrawal
result = client.initiate_withdrawal(asset_id='USDC', amount='100', external_wallet_id='<id from get_external_wallets>', from_account='trading', note='')
from_account is trading or custody (fiat supports trading only). The response contains transfer with status (PENDING, COMPLETED, REJECTED), transaction_id and message.
14. Initiate transfer
result = client.initiate_transfer(asset_id='USDC', amount='100', from_account='trading', note='')
Moves funds between the custody and trading accounts; the response has the same shape as Initiate Withdrawal.
Errors
Non-200 responses raise zerocap_api.ZerocapAPIError with status_code and body. Common cases: 401 (Unauthorized., encryption check is fail, Unauthorized IP address., invalid timestamp when timestamp is not an integer), 408 (timestamp skew over 30 s), 422 (validation, including characters outside the allowed set in symbol, currency, asset_id or quote_id), 429 (limit of 50 requests/second per endpoint per IP).
Websocket
The server pushes an unsolicited {"type": "message", "message": "pong"} roughly every 5 s. Send any message at least every 30 s
(the SDK's heartbeat thread sends one every 5 s); after 30 s of silence the server sends {"type": "error", "error_code": 400, "error_message": "ping timeout"}
and closes the connection. See https://docs.zerocap.com for the full Websocket Overview.
Order trades is always a list. price timestamps are float seconds; order and trade timestamps are integer milliseconds.
import time
from zerocap_api import ZerocapWebsocketClient
# API key and secret are required, please contact zerocap to register.
api_key = "***"
api_secret = "***"
websocket = ZerocapWebsocketClient(api_key, api_secret, env='sandbox')
# Create Ws Connection
timestamp = int(time.time())
websocket_connect = websocket.create_connection(timestamp)
connect_result = websocket.recv(websocket_connect)
print(connect_result)
create_connection() opens the socket and returns an iterator of raw messages. recv(websocket_connect) reads the
next message from that iterator; recv() with no argument reads straight from the live socket, so keeping the
iterator is optional. The connection stays open until websocket.close() or websocket_connect.close() is called;
calling create_connection() again closes the previous connection first.
Response example:
{
"type": "message",
"message":"Successfully connected."
}
{
"type": "error",
"error_code": 401,
"error_message":"Unauthorized"
}
1. Subscribe to market data
websocket.send({"type": 'price', "symbols": ["USDT/AUD"]})
while True:
# Get messages
message = websocket.recv(websocket_connect)
print(f"Receiving message from server: \n{message}")
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| type | true | str | Subscription type | price |
| symbols | true | list | Transaction pairs | ["USDT/AUD"] |
| is_subscribe | false | bool | false to unsubscribe (default true) |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
header={"api-key": api_key, "signature": signature, "timestamp": str(timestamp)}
wss://dma-ws.zerocap.com/v2 # prod
wss://sandbox-ws.zerocap.com/v2 # sandbox
Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| type | true | str | type | price, message, error |
| data | false | json | data | |
| data['timestamp'] | true | float | time (seconds) | |
| data['symbol'] | true | str | symbol | |
| data['exchange'] | true | str | exchange | |
| data['bids'] | true | list | bids | |
| data['asks'] | true | list | asks | |
| message | false | str | description | |
| error_code | false | int | error code | |
| error_message | false | str | error message |
Response example:
{
"type": "error",
"error_code": 400,
"error_message":"invalid message"
}
{
"type": "message",
"message":"price Subscription successful."
}
{
"type": "message",
"message": "pong"
}
{
"type": "price",
"data": {
'timestamp': 1692340935.4283478,
'symbol': 'USDT/AUD',
'exchange': 'zerocap',
'bids': [
[1.47386, 5000.0],
[1.47238, 10000.0],
[1.4709, 20000.0],
[1.46941, 30000.0]
],
'asks': [
[1.57236, 5000.0],
[1.57392, 10000.0],
[1.57548, 20000.0],
[1.57705, 30000.0]
]
}
}
{
"type": "message",
"message":"Price stream unavailable."
}
2. Subscribe to order updates
websocket.send({"type": 'order'})
while True:
# Get messages
message = websocket.recv(websocket_connect)
print(f"Receiving message from server: \n{message}")
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| type | true | str | Subscribed type | order |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
header={"api-key": api_key, "signature": signature, "timestamp": str(timestamp)}
wss://dma-ws.zerocap.com/v2 # prod
wss://sandbox-ws.zerocap.com/v2 # sandbox
order Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| type | true | str | type | order, message, error |
| data | false | json | data | |
| data['id'] | true | str | id | |
| data['timestamp'] | true | long | timestamp (ms) | |
| data['last_trade_timestamp'] | true | long | last_trade_timestamp (ms) | |
| data['status'] | true | str | status | |
| data['symbol'] | true | str | symbol | |
| data['type'] | true | str | type | |
| data['time_in_force'] | true | str | time_in_force | |
| data['side'] | true | str | side | |
| data['price'] | true | float | price | |
| data['average'] | true | float | average | |
| data['amount'] | true | float | amount | |
| data['filled'] | true | float | filled | |
| data['remaining'] | true | float | remaining | |
| data['cost'] | true | float | cost | |
| data['error_message'] | true | str | error_message | |
| data['fee'] | true | float | fee | |
| data['trades'] | true | list | trades | |
| message | false | str | description | |
| error_code | false | int | error code | |
| error_message | false | str | error message |
Response example:
{
"type": "error",
"error_code": 400,
"error_message":"invalid message"
}
{
"type": "message",
"message":"order Subscription successful."
}
{
"type": "message",
"message": "pong"
}
{
"type":"order",
"data":{
"id":"f7fc4e4f-c099-4b18-a231-f032adc8ae87",
"timestamp":1692354083000,
"last_trade_timestamp":1692354083000,
"status":"open",
"symbol":"USDT/AUD",
"type":"limit",
"time_in_force":"FOK",
"side":"buy",
"price":3,
"average":0,
"amount":3,
"filled":0,
"remaining":3,
"cost":9,
"error_message":"",
"fee":0,
"trades":[]
}
}
{
"type":"order",
"data":{
"id":"f7fc4e4f-c099-4b18-a231-f032adc8ae87",
"timestamp":1692354083000,
"last_trade_timestamp":1692354083000,
"status":"closed",
"symbol":"USDT/AUD",
"type":"limit",
"time_in_force":"FOK",
"side":"buy",
"price":3,
"average":1.474899,
"amount":3,
"filled":3,
"remaining":0,
"cost":9,
"error_message":"",
"fee":0,
"trades":[{
"id":"fa9cbef5-54ce-4a3a-8115-3db8af1f1617",
"timestamp":1692354083000,
"symbol":"USDT/AUD",
"order":"f7fc4e4f-c099-4b18-a231-f032adc8ae87",
"type":"limit",
"side":"buy",
"taker_or_maker":"taker",
"price":1.474899,
"amount":3,
"cost":4.424,
"fee":0
}]
}
}
3. Subscribe to trades
websocket.send({"type": 'trade'})
while True:
# Get messages
message = websocket.recv(websocket_connect)
print(f"Receiving message from server: \n{message}")
Request parameters:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| type | true | str | Subscribed type | trade |
Request parameters: examples (cannot be used directly, you need to replace your own parameters)
header={"api-key": api_key, "signature": signature, "timestamp": str(timestamp)}
wss://dma-ws.zerocap.com/v2 # prod
wss://sandbox-ws.zerocap.com/v2 # sandbox
Transaction Record Response data:
| Parameter | required | data type | describe | Value range |
|---|---|---|---|---|
| type | true | str | type | trade,message, error |
| data | false | json | data | |
| data['id'] | true | str | id | |
| data['timestamp'] | true | long | timestamp (ms) | |
| data['symbol'] | true | str | symbol | |
| data['order'] | true | str | order | |
| data['type'] | true | str | type | |
| data['side'] | true | str | side | |
| data['taker_or_maker'] | true | str | taker_or_maker | |
| data['price'] | true | float | price | |
| data['amount'] | true | float | amount | |
| data['cost'] | true | float | cost | |
| data['fee'] | true | float | fee | |
| data['client_order_id'] | true | str | client_order_id | |
| message | false | str | description | |
| error_code | false | int | error code | |
| error_message | false | str | error message |
Response example:
{
"type": "error",
"error_code": 400,
"error_message":"invalid message"
}
{
"type": "message",
"message":"trade Subscription successful."
}
{
"type": "message",
"message": "pong"
}
{
"type":"trade",
"data":{
"id":"fa9cbef5-54ce-4a3a-8115-3db8af1f1617",
"timestamp":1692354083000,
"symbol":"USDT/AUD",
"order":"f7fc4e4f-c099-4b18-a231-f032adc8ae87",
"type":"limit",
"side":"buy",
"taker_or_maker":"taker",
"price":1.474899,
"amount":3,
"cost":4.424,
"fee":0,
"client_order_id":""
}
}
Changelog
0.1.37
create_orderacceptscoinroutes_customer_idagain, as a deprecated keyword (defaultNone, sent only when given), so integrations written for 0.1.35 and earlier keep working. 0.1.36 had removed it, which made those calls fail withTypeError.- Websocket: discarding the iterator returned by
create_connection()no longer closes the connection. The socket stays open untilclose()is called on the client or on the iterator, or a newcreate_connection()replaces it, socreate_connection()followed byrecv()/send()without arguments works. - Packaging: wheel published alongside the sdist,
SourceandChangelogproject links, Python 3.8 to 3.13 classifiers. - README: introduction and table of contents, REST sample without unused imports, Get Time without authentication headers, integer
start_datetime/end_datetime/page/limitin fetch_orders (andpage/limitin get_transfers), sandbox websocket URL next to production.
0.1.36 (2026-10-16)
- Websocket errors keep their original type (e.g.
websockets.exceptions.ConnectionClosed) instead of being wrapped in a bareException. request_for_quote:symbol,sideandamountare required, matching the API.create_order: thecoinroutes_customer_idargument is removed (it only applied to the Coinroutes integration and is no longer part of the public API).- Order channel
tradesis always a list, and messages no longer carryinternal_extra_data(server-side change). - Fix websocket reconnect: breaking out of a
create_connection()generator and callingcreate_connection()again no longer closes the new connection when the old generator is garbage collected. Each generator and heartbeat thread is now bound to its own socket, and a newcreate_connection()closes the previous connection first.
0.1.35 (2026-10-16)
- Only
prodandsandboxenvironments are supported; unknownenvraisesValueError. - REST client: default 30 s timeout (
timeout=argument), non-200 responses raiseZerocapAPIError(status_code,body),priceis now required increate_order,coinroutes_customer_idis deprecated and only sent when set. - New REST methods:
request_for_firm_quote,accept_quote,get_external_wallets,initiate_withdrawal,initiate_transfer;request_for_quotegainedcurrency. - README: removed internal fields from examples (
counterparty,order_from), snake_case field names,amountin request_for_quote,crypto_transactionsin get_transfers, websocketsymbols/is_subscribe/heartbeat notes. get_timeis sent without authentication headers.- Websocket client: socket opens in
create_connection()(sosend()works immediately), heartbeat thread is a daemon and stops onclose();verify_identity()removed.
Metadata
Release files for zerocap-api 0.1.38
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| zerocap_api-0.1.38.tar.gz | 33.2 kB | Without provenance | Details |
Release files / zerocap_api-0.1.38.tar.gz
| Download URL | zerocap_api-0.1.38.tar.gz |
|---|---|
| Size | 33.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e88eed7608fa2018767aeee1af6eb9e85c228cfbc285cc2ae32edcf30141b207
|
|
BLAKE2b-256 checksum How to use checksums |
e0c4e83c8ed0aecd6a48cf91225309428b49d5166d94a7887002988cf47700de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.10
|
Security for zerocap-api 0.1.38
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.