API

Buildix is an institutional-grade orderflow analytics platform for DEX and CEX perpetual trading. Access real-time CVD, VPIN, OBI, whale tracking and signal data over a REST API from Python, JavaScript or cURL. All endpoints are documented below. There is no WebSocket: the platform is serverless and holds no connections, so consumers poll, and the feed endpoints report their producer cadence so you know how often that is worth doing.

AI ASSISTANT INTEGRATION (MCP)

NEW

Add Buildix to Claude, ChatGPT, Le Chat, Perplexity, Grok or any MCP client. Free mode: one URL, five read-only tools, no account and no key. API mode: the same API keys and daily quota as the REST API, seven plan-gated tools with raw values.

https://www.buildix.trade/api/mcp/public

Both modes and the setup for each assistant: AI Integrations (API mode).

Funding annualization, October 2, 2026. fundingAnnualized (screener, pair, signals, CSV export) and funding_annualized_pct (alert webhooks) are now annualized on the venue's real settlement interval. Hyperliquid and dYdX settle hourly, so on Hyperliquid the values are about 8 times the previous ones for the same rate. funding, the raw hourly rate, does not change. In /api/v1/funding-arb every venue carries intervalHours, annualized uses it, and spread and spreadAnnualized compare hourly equivalent rates.

DAILY QUOTA BY PLAN
FREE
20
req / day
Open endpoints
TRIAL
500
req / day
Open endpoints
STARTER
500
req / day
Open endpoints
TRADER
2,000
req / day
+ signals
PRO
5,000
req / day
+ smart money, entry signals
WHALE
2,000
req / day
+ deep view, CVD, liq map, funding arb, wallets
API
50,000
req / day
Same surface as Whale, highest quota

Counted per API key, reset at Europe/Rome midnight (not UTC). Exhausting it returns HTTP 429 with a Retry-After header holding the seconds until the reset. Whale moved from 50,000 to 2,000 requests per day in September 2026 and the 50,000 allowance moved to the API plan; a Whale subscription that started before 8 September 2026 keeps 50,000 per day for 60 days from that date. Read /api/v1/usage for the limit actually applied to your key.

BURST LIMIT PER MINUTE
/api/v1/deep-view/*
10 req / min
/api/v1/cvd/*
10 req / min
all other /api/v1/*
60 req / min
/api/mcp
60 req / min

The burst guard runs at the edge and does not depend on your plan. It is keyed by identity: your IP address, or your IP plus the public prefix of the key when you send one, so a shared office address is not punished for one noisy key. Going over returns HTTP 429 with the window in the body and an accurate Retry-After.

ENDPOINTS
GET/api/v1/screener
OPEN · 60/min

Every tradable Hyperliquid perpetual with mark price, 24h change, 24h volume, open interest in USD and funding (raw hourly rate + annualized as rate x 24 x 365). No API key required; a key only raises the daily quota.

EXAMPLE
curl "https://www.buildix.trade/api/v1/screener"

# A key is optional here, and raises the daily quota:
curl "https://www.buildix.trade/api/v1/screener" \
  -H "Authorization: Bearer YOUR_API_KEY"
AUTHENTICATION

Generate an API key from your Dashboard → API Keys. Include it in every request as a Bearer token. Keys look like bx_ followed by 32 hex characters — there is no bx_live_ / bx_test_ split.

Authorization: Bearer bx_0123456789abcdef0123456789abcdef

Two other spellings are accepted, in this order of priority: the header x-api-key: bx_..., and, only where a client cannot set a custom header at all, the query parameter ?api_key=bx_.... A key in a URL can be captured by your own client logs and by any proxy in between, so keep the query form for connectors that leave you no choice and give those a dedicated key.

/api/v1/screener and /api/v1/pair/{symbol} answer without a key; a key on those only raises the daily quota. Every other endpoint requires one. An invalid or revoked key returns 401, a plan below the endpoint returns 403 naming the tier required, and an exhausted daily quota returns 429.

WEBHOOKS

Buildix can POST events to your own server: Entry Signals, their outcome four hours later, and your alerts. Register an endpoint in Dashboard → Alerts (5 endpoints on Pro, 20 on Whale and API). Each endpoint gets a signing secret, shown once, that you can rotate.

EVENTS
  • entry_signal.created: a new Entry Signal matching an Entry Signal alert that uses the endpoint (same pairs, timeframe and minimum grade as the Telegram and email channel). Pro and above. On HIP-3 markets (symbols such as xyz:NVDA) a signal whose bar falls outside the market's trading session is sent with its grade lowered one step and two extra fields in data: session ("closed") and grade_before_session. Crypto signals and open-session signals never carry them.
  • signal.outcome: four hours after each delivered signal, the move in the signal's direction, the best and worst excursion and which level was touched first. Computed from the 5m bars Buildix already holds, with the same price rule as the public channel follow up.
  • alert.triggered: an alert (price, screener, sweep, delta flip, drawing) whose webhook URL is a registered endpoint. data carries the same fields as the previous flat payload, plus alert_kind.
  • test: sent by the Send test event button.
ENVELOPE

Every event has the same envelope. id is stable: a retry of the same event carries the same id, so store it and ignore duplicates. New fields may be added to data; a breaking change would ship as version "2".

{
  "id": "evt_9f2c41d0b6a84e5f8c1d2e3f4a5b6c7d",
  "type": "entry_signal.created",
  "version": "1",
  "created_at": "2026-09-26T10:15:04.211Z",
  "data": {
    "signal_id": "BTC-15m-1758880800000-long",
    "symbol": "BTC",
    "timeframe": "15m",
    "side": "long",
    "grade": "A",
    "score": 0.81,
    "bar_time": "2026-09-26T10:00:00.000Z",
    "regime": "trend_up",
    "confirmed": true,
    "flow_source": "trades",
    "logics": { "liquidity_grab": true, "flow_rejection": true, "absorption": false,
                "cvd_divergence": true, "structure_shift": false, "level_confluence": true },
    "plan": { "entry": 64210.5, "stop": 63880.0, "t1": 64706.0, "t2": 65201.5, "r_t1": 1.5, "r_t2": 3 },
    "price_at_signal": 64215.0,
    "chart_url": "https://www.buildix.trade/pair/BTC"
  }
}
{
  "id": "evt_0b7e...",
  "type": "signal.outcome",
  "version": "1",
  "created_at": "2026-09-26T14:15:30.002Z",
  "data": {
    "entry_event_id": "evt_9f2c41d0b6a84e5f8c1d2e3f4a5b6c7d",
    "signal_id": "BTC-15m-1758880800000-long",
    "symbol": "BTC", "timeframe": "15m", "side": "long", "grade": "A",
    "horizon": "4h",
    "signaled_at": "2026-09-26T10:15:04.211Z",
    "evaluated_at": "2026-09-26T14:15:30.002Z",
    "price_at_signal": 64215.0,
    "price_after": 64890.0,
    "move_pct": 1.0512,
    "max_favorable_pct": 1.4201,
    "max_adverse_pct": -0.3105,
    "first_level_hit": "t1",
    "t2_hit": false
  }
}

first_level_hit is stop, t1, none, or both_same_bar when one 5m bar spans both levels and the order inside the bar is unknown.

HEADERS AND SIGNATURE
Content-Type: application/json
X-Buildix-Event: entry_signal.created
X-Buildix-Event-Id: evt_9f2c41d0b6a84e5f8c1d2e3f4a5b6c7d
X-Buildix-Delivery: <uuid of this delivery>
X-Buildix-Attempt: 1
X-Buildix-Timestamp: 1758881704
X-Buildix-Signature: v1=<hex HMAC-SHA256(secret, "<timestamp>.<raw body>")>

Compute the HMAC over the timestamp, a dot and the raw request body exactly as received, and compare in constant time. Reject a timestamp more than 300 seconds away from your clock (replay protection) and an event id you already handled. For 24 hours after a rotation the header carries two entries, v1=<new>,v1=<old>: accept the request when any entry matches.

NODE
// Node 18+ (Express). Verify on the RAW body, before JSON parsing.
import crypto from 'node:crypto';
import express from 'express';

const SECRET = process.env.BUILDIX_WEBHOOK_SECRET; // whsec_...
const TOLERANCE_S = 300;
const seen = new Set(); // use your database in production

function verify(rawBody, timestamp, signatureHeader) {
  if (!timestamp || !signatureHeader) return false;
  const ts = Number(timestamp);
  if (!Number.isInteger(ts) || Math.abs(Date.now() / 1000 - ts) > TOLERANCE_S) return false;
  const expected = crypto.createHmac('sha256', SECRET).update(`${ts}.${rawBody}`).digest();
  return signatureHeader.split(',').some((part) => {
    const [scheme, hex] = part.trim().split('=');
    if (scheme !== 'v1' || !/^[0-9a-f]{64}$/.test(hex || '')) return false;
    return crypto.timingSafeEqual(Buffer.from(hex, 'hex'), expected);
  });
}

const app = express();
app.post('/buildix', express.raw({ type: 'application/json' }), (req, res) => {
  const raw = req.body.toString('utf8');
  if (!verify(raw, req.get('X-Buildix-Timestamp'), req.get('X-Buildix-Signature'))) {
    return res.status(401).end();
  }
  const event = JSON.parse(raw);
  if (seen.has(event.id)) return res.status(200).end(); // retry of an event already handled
  seen.add(event.id);
  res.status(200).end(); // answer fast, work after
  // handle event.type / event.data here
});
app.listen(3000);
PYTHON
# Python 3.10+ (Flask). Verify on the RAW body, before JSON parsing.
import hashlib, hmac, json, os, time
from flask import Flask, request, abort

SECRET = os.environ["BUILDIX_WEBHOOK_SECRET"].encode()  # whsec_...
TOLERANCE_S = 300
seen = set()  # use your database in production

def verify(raw: bytes, timestamp: str | None, signature_header: str | None) -> bool:
    if not timestamp or not signature_header or not timestamp.isdigit():
        return False
    if abs(time.time() - int(timestamp)) > TOLERANCE_S:
        return False
    expected = hmac.new(SECRET, f"{timestamp}.".encode() + raw, hashlib.sha256).hexdigest()
    for part in signature_header.split(","):
        scheme, _, value = part.strip().partition("=")
        if scheme == "v1" and hmac.compare_digest(value, expected):
            return True
    return False

app = Flask(__name__)

@app.post("/buildix")
def buildix():
    raw = request.get_data()
    if not verify(raw, request.headers.get("X-Buildix-Timestamp"), request.headers.get("X-Buildix-Signature")):
        abort(401)
    event = json.loads(raw)
    if event["id"] in seen:
        return "", 200  # retry of an event already handled
    seen.add(event["id"])
    # handle event["type"] / event["data"] here
    return "", 200
DELIVERY
  • https only, port 443, public addresses only (checked on every delivery), redirects are not followed, 5 second timeout, request body up to 64 KB. Answer with any 2xx as soon as you have stored the event.
  • A failed delivery is retried after 1 min, 5 min, 30 min, 2 h (5 attempts in total). A 410, or a 404 from Discord or Slack, means the webhook is gone and the endpoint is disabled at once.
  • After 20 failed deliveries in a row spanning at least 24 hours the endpoint is disabled; you get an in-app notification and an email, and you can turn it back on from the dashboard.
  • Limits: an alert sends at most one webhook every 5 minutes, whatever its cooldown (email, Telegram and in-app keep the alert's own cooldown). When 50 deliveries of an endpoint are already waiting for a retry, new events for that endpoint are dropped until the backlog clears (older ones keep their retries; the delivery log shows one backlog line per hour). An account receives at most 2,000 webhook events per day (Europe/Rome day).
  • Discord and Slack incoming webhook URLs receive a formatted message (embed or blocks) instead of the raw JSON.
  • The dashboard shows the last 50 deliveries of each endpoint (kept 3 days). Send test event is limited to 5 per minute and 20 per day.
  • An alert webhook URL that is not registered as an endpoint keeps receiving the previous flat, unsigned JSON. Register the same URL to switch it to the signed envelope.

Need API access?

The screener and pair endpoints are open, so you can build against them before you pick a plan. A key raises the daily quota and unlocks the gated endpoints; the burst limit per minute is the same on every plan.