Skip to main content

Reference Client

A small helper you copy once into your project and then reuse for every authenticated request. It handles signing, the auth headers, and the timestamp for you, so you don't have to think about authentication again.

Every endpoint page in this documentation calls these helpers — sign_request(...) (Python / Go), client.send(...) (Java), or signRequest(...) (Node.js). If your code matches what's on the page, it will work as shown.

How it works

Given a method, path, optional query parameters, and optional body, the helper:

  1. Builds the URL-decoded path with query string.
  2. Computes signed_message = METHOD + path + epoch.
  3. Signs the message with your Ed25519 secret key.
  4. Returns the headers (with the signature, API key, and epoch) plus the final URL path you should hit.

You then make the HTTP request as normal.

For the exact bytes that get signed, see Authentication.

The helper

import time
import urllib.parse
import requests
from cryptography.hazmat.primitives.asymmetric import ed25519

API_KEY = "<your api key>" # hex
SECRET_KEY = "<your secret key>" # hex

BASE_URL = "https://coinswitch.co"

def sign_request(method, path, params=None):
"""
Build the headers and final URL path for an authenticated CoinSwitch
request. Pass the returned dict as `headers=` and the returned `path`
as the URL (after BASE_URL).

method — "GET" / "POST" / "DELETE"
path — endpoint path, e.g. "/trade/api/v2/order"
params — query parameters dict (for GET requests with filters)
"""
method = method.upper()

if params:
sep = "&" if "?" in path else "?"
path = path + sep + urllib.parse.urlencode(params)
decoded_path = urllib.parse.unquote_plus(path)

epoch = str(int(time.time() * 1000))
message = method + decoded_path + epoch

secret = ed25519.Ed25519PrivateKey.from_private_bytes(bytes.fromhex(SECRET_KEY))
signature = secret.sign(message.encode("utf-8")).hex()

headers = {
"Content-Type": "application/json",
"X-AUTH-APIKEY": API_KEY,
"X-AUTH-SIGNATURE": signature,
"X-AUTH-EPOCH": epoch,
}
return headers, decoded_path

Required:

  • Python 3.9+
  • cryptography (for Ed25519): pip install cryptography
  • requests (or any HTTP client): pip install requests

Usage

# Place a spot order
body = {
"side": "sell",
"symbol": "BTC/USDT",
"type": "limit",
"price": 26000,
"quantity": 0.0009,
"exchange": "c2c1",
}
headers, path = sign_request("POST", "/trade/api/v2/order")
response = requests.post(BASE_URL + path, headers=headers, json=body)
print(response.json())

HFT and Futures notes

  • HFT: same helper, different base URL — change BASE_URL to https://dma.coinswitch.co. HFT requires X-AUTH-EPOCH (the helper always sends it, so you're fine).
  • Futures: same base URL, just hit /trade/api/v2/futures/... paths.

WebSocket signing

Spot and Futures WebSockets (wss://ws.coinswitch.co/...) are public-only at the socket layer — the connection itself doesn't require a signature. The auth happens in the Socket.IO handshake's auth.apiKey, which is your CoinSwitch API key. Private streams (Spot order updates, Spot balance updates) read your API key from there. See the per-page guides under Spot › WebSockets.

For HFT private NATS streams, you fetch credentials from a REST endpoint and pass them to the WebSocket auth message. The helper below wraps that fetch.

# Requires the sign_request helper above.

def get_socket_credentials(expires_in_seconds=300):
"""
Fetch credentials for the HFT private NATS stream.
Returns {"api_key": ..., "expires": ..., "signature": ...}.
Pass these directly to the WebSocket auth message;
do not log or persist them.
"""
params = {"expires_in_seconds": expires_in_seconds}
headers, path = sign_request(
"GET", "/dma/api/v1/socket/signature", params)
r = requests.get(BASE_URL + path, headers=headers)
r.raise_for_status()
return r.json()

The returned signature is computed on our side — you don't compute it yourself; just pass it through to the WebSocket auth message. See HFT › Private Streams for how to use the result on the WebSocket.