Trading API · Authentication

Two ways to authenticate

Bitrus supports two authentication mechanisms. Human users (Client Operators) sign in with email and password. Programmatic clients (Client Agents) authenticate with a detached signature. Both flows return the same JWT bearer token; all subsequent API calls authenticate via that token.

Password login

For users issued an email and password by Bitrus (Employees, Employee Managers, Client Operators).

POST /api/v1/auth/password-login
Client Operators (human dashboard users)
Submit email and password. On success, returns a JWT bearer token valid for 60 minutes.

Request

curl -X POST https://api.bitrus.com/api/v1/auth/password-login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ops@bitrus.com",
    "password": "Sup3rS3cret!"
  }'

Response

1 keys
"response": {
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
}

Signed request login

Send {user_id, timestamp} as JSON body and a detached signature in the X-Signature header. The server canonicalises the body via JSON with sorted keys and the separators (',', ':'), then verifies the signature against the agent's pre-registered public key. The timestamp must be within 5 seconds of the server clock to prevent replay.

POST /api/v1/auth/signature-login
Client Agents (programmatic API consumers)
1

Build the request body

Two fields: user_id (the agent UUID issued by Bitrus) and timestamp (current UTC, ISO-8601).

2 keys
"body": {
"user_id": "9c6f3e7e-2b3d-4ef0-9c0a-3a8c0d2c0f10",
"timestamp": "2026-04-27T15:42:18.123456+00:00"
}
2

Canonicalize

Sort the keys and serialize with no whitespace using separators (',', ':'). The result is the message you sign — and the exact bytes you must send.

{"timestamp":"2026-04-27T15:42:18.123456+00:00","user_id":"9c6f3e7e-2b3d-4ef0-9c0a-3a8c0d2c0f10"}
3

Sign with your private key

HMAC-SHA256 over the canonical bytes. Hex-encode the digest and place it in the X-Signature header.

Python

import hmac
import hashlib
import json
from datetime import datetime, timezone
import requests

PRIVATE_KEY = b"<your raw private key bytes>"
USER_ID = "9c6f3e7e-2b3d-4ef0-9c0a-3a8c0d2c0f10"

body = {
    "user_id": USER_ID,
    "timestamp": datetime.now(timezone.utc).isoformat(),
}

# Canonical JSON: sorted keys, no whitespace
canonical = json.dumps(body, sort_keys=True, separators=(",", ":"))

signature = hmac.new(
    PRIVATE_KEY,
    canonical.encode("utf-8"),
    hashlib.sha256,
).hexdigest()

response = requests.post(
    "https://api.bitrus.com/api/v1/auth/signature-login",
    headers={"X-Signature": signature, "Content-Type": "application/json"},
    data=canonical,
)
response.raise_for_status()
print(response.json()["data"]["access_token"])

JavaScript

import { createHmac } from "node:crypto"

const privateKey = process.env.BITRUS_PRIVATE_KEY!
const userId = process.env.BITRUS_USER_ID!

const body = {
  user_id: userId,
  timestamp: new Date().toISOString(),
}

const canonical = JSON.stringify(
  Object.fromEntries(Object.entries(body).sort()),
)

const signature = createHmac("sha256", privateKey)
  .update(canonical)
  .digest("hex")

const response = await fetch(
  "https://api.bitrus.com/api/v1/auth/signature-login",
  {
    method: "POST",
    headers: {
      "X-Signature": signature,
      "Content-Type": "application/json",
    },
    body: canonical,
  },
)

const { data } = await response.json()
console.log(data.access_token)
4

Send and unwrap the JWT

Bitrus verifies the signature with the registered public key. On success you receive a 60-minute JWT bearer token.

1 keys
"response": {
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
}

Using the JWT

Both flows return the same shape. Attach it to subsequent requests via the standard Authorization header.

AlgorithmHS256
Token lifetime60 minutes
Refresh endpointNot supported — re-authenticate on expiry
Server-side invalidationTokens are stateless until they expire

Authenticated request

curl https://api.bitrus.com/api/v1/quotes/ \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json"

Every response also returns X-Transaction-Id Every response includes an X-Transaction-Id header (a UUID) and an X-Process-Time header in milliseconds. Include the transaction id when contacting support.