TradeClaw

Open-source AI market intelligence for traders who prefer evidence over noise.

Self-hosted by default

Product

  • Dashboard
  • Screener
  • Backtest
  • Track record
  • Live demo

Transparency

  • What we tested and killed
  • Methodology
  • Why long-term
  • Open data
  • Calibration

Resources

  • Blog
  • Docs
  • API reference
  • How it works
  • FAQ
  • Glossary

Community

  • Discord
  • Weekly digest
  • Contribute
  • Contributors
  • Sponsors

Open source

  • GitHub repo
  • Star history
  • Self-host guide
  • Security
  • Data freshness
  • Roadmap

© 2026 TradeClaw. MIT licensed.

Terms|Privacy|Trading involves risk. Signals are informational only and are not financial advice.
DashboardScreenerCopilotTrack Record
TradeClaw
Documentation

Getting Started

  • Overview
  • Installation
  • Configuration
  • Self-Hosting

Core Features

  • Trading Signals
  • Paper Trading
  • Strategy Builder

Integrations

  • API Reference
  • Webhooks
  • Telegram Bot
  • Plugins
  • Embedding

Project

  • Contributing
  • Changelog
GitHubApp Dashboard

Integrations

Webhooks

TradeClaw can push signal and price events to any URL — signals fire on the 5-minute cron, price events stream within seconds for crypto and ≤60s for FX/metals/stocks. Each delivery is signed with HMAC-SHA256 so your receiver can verify the payload came from your instance — not a third party.

Setup via the UI

Navigate to Settings → Webhooks in the dashboard. Click Add Webhook, enter your endpoint URL, optionally provide a secret, and save. You can test delivery immediately from the same panel.

1

Enter URL

HTTPS endpoint that accepts POST requests

2

Set Secret

Optional. Used to sign and verify payloads

3

Test Delivery

Send a sample payload to confirm connectivity

Or create via API
curl -X POST https://your-instance.com/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/tradeclaw",
    "name": "My Signal Receiver",
    "secret": "whsec_your_secret_here"
  }'

# Response
{
  "id": "wh_abc123",
  "url": "https://your-app.com/webhooks/tradeclaw",
  "name": "My Signal Receiver",
  "enabled": true,
  "createdAt": "2026-03-27T12:00:00Z"
}

HMAC-SHA256 Signing

Every delivery includes an X-TradeClaw-Signature header. The value is the HMAC-SHA256 of the raw request body using your webhook secret as the key, encoded as a hex string prefixed with sha256=.

Header: X-TradeClaw-Signature

Value: sha256=<hex(HMAC-SHA256(secret, rawBody))>

Also includes: X-TradeClaw-Delivery (unique delivery ID)

Also includes: X-TradeClaw-Event (event type string)

Important: Always verify the signature before processing the payload. Use a constant-time comparison to prevent timing attacks.
Node.js — signature verification
const crypto = require('crypto');

function verifySignature(secret, rawBody, signatureHeader) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'utf8'),
    Buffer.from(signatureHeader, 'utf8')
  );
}

// Express receiver
app.post('/webhooks/tradeclaw', express.raw({ type: '*/*' }), (req, res) => {
  const sig = req.headers['x-tradeclaw-signature'];
  if (!verifySignature(process.env.WEBHOOK_SECRET, req.body, sig)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body.toString());
  console.log('Event type:', event.type);
  res.sendStatus(200);
});

Payload Schema

All webhook payloads share a common envelope. The data field contains the event-specific object.

typescript
interface WebhookPayload {
  id: string;          // Unique delivery ID (same as X-TradeClaw-Delivery)
  type: WebhookEventType;
  createdAt: string;   // ISO 8601
  data: SignalEvent | PriceEvent | AlertEvent;
}

type WebhookEventType =
  | 'signal.created'
  | 'signal.updated'
  | 'price.alert'
  | 'tp.hit'
  | 'sl.hit';

// signal.created example
{
  "id": "del_xyz789",
  "type": "signal.created",
  "createdAt": "2026-03-27T14:30:00Z",
  "data": {
    "id": "sig_abc123",
    "symbol": "XAUUSD",
    "timeframe": "H1",
    "direction": "BUY",
    "confidence": 87,
    "entryPrice": 2345.50,
    "tp1": 2360.00, "tp2": 2374.50, "tp3": 2389.00,
    "sl": 2331.00
  }
}

Discord & Slack Auto-Formatting

TradeClaw detects Discord and Slack webhook URLs automatically and sends rich formatted messages instead of raw JSON — no middleware required.

Discord

Sends an embed with colored sidebar (green for BUY, red for SELL), symbol, direction, confidence, entry, TP levels, and SL. URLs matching discord.com/api/webhooks are auto-detected.

Slack

Sends a Block Kit message with sections and context blocks. URLs matching hooks.slack.com are auto-detected and formatted accordingly.

Retry Logic

If your endpoint returns a non-2xx status code or times out, TradeClaw retries with exponential backoff. A delivery is considered failed after 3 attempts.

AttemptDelayTimeout
1st (initial)Immediate5s
2nd5 seconds5s
3rd (final)25 seconds5s

View delivery history and retry status at GET /api/webhooks/[id]/deliveries. Trigger a manual redeliver with POST /api/webhooks/deliver.

Rate Limiting

Webhook deliveries are rate-limited to one per 5 seconds per endpoint URL. High-frequency price events are batched before dispatch to avoid overwhelming receivers. Signal events are never batched — each signal triggers an individual delivery.

Max delivery rate: 1 per 5 seconds per URL

Signal events: Immediate, never batched

Price events: Batched into 5s windows

Max webhooks per instance: 20

Python Flask Receiver

webhook_receiver.py
import hashlib
import hmac
import os
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = os.environ['WEBHOOK_SECRET']

def verify_signature(secret: str, body: bytes, signature: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.route('/webhooks/tradeclaw', methods=['POST'])
def receive_webhook():
    sig = request.headers.get('X-TradeClaw-Signature', '')
    if not verify_signature(WEBHOOK_SECRET, request.data, sig):
        abort(401)

    event = request.get_json()
    event_type = event.get('type')

    if event_type == 'signal.created':
        data = event['data']
        print(f"New signal: {data['symbol']} {data['direction']} @ {data['confidence']}%")
    elif event_type == 'price.alert':
        print(f"Alert triggered: {event['data']}")

    return '', 200

if __name__ == '__main__':
    app.run(port=3001)
PreviousAPI ReferenceNextTelegram Bot
Edit this page on GitHub