This document describes the HTTP and WebSocket endpoints exposed by the Clodds gateway.
By default the gateway binds to loopback and listens on port 18789.
http://127.0.0.1:18789
- HTTP endpoints do not enforce authentication by default. Protect the gateway with network controls or a reverse proxy if you expose it publicly.
- WebChat supports an optional token. Set
WEBCHAT_TOKENand send it in the WebSocket auth message. - Webhooks require HMAC signatures by default. See the webhook section below.
Skills and agents running inside Clodds call services directly — no HTTP needed. The REST API is for everything external: dashboards, mobile apps, automation scripts, Telegram/Discord bots, monitoring (Grafana/Datadog), AI agent integrations (MCP tools, LangChain), multi-instance orchestration, and copy trading platforms. See API_REFERENCE.md for detailed examples.
Basic health check.
Response:
{ "status": "ok", "timestamp": 1730000000000 }
API info and supported endpoints.
Response:
{
"name": "clodds",
"version": "0.3.10",
"description": "AI assistant for prediction markets",
"endpoints": { "websocket": "/ws", "webchat": "/chat", "health": "/health" }
}
Returns a simple HTML client that connects to the WebChat WebSocket endpoint (/chat).
Generic webhook endpoint for automation hooks.
Headers:
x-webhook-signatureorx-hub-signature-256(required by default)
Signature:
- HMAC SHA-256 hex digest of the raw request body using the webhook secret.
- To disable signature requirements, set
CLODDS_WEBHOOK_REQUIRE_SIGNATURE=0.
Responses:
200 { "ok": true }on success401for missing/invalid signatures404for unknown webhook paths429if rate limited
Channel webhook entrypoint for platforms like Teams, Google Chat, etc.
Behavior:
- Forwards the JSON body to the configured channel adapter.
- Returns
404if that platform handler is not configured.
Search the market index (requires marketIndex.enabled).
Query parameters:
q(string, required): search textplatform(string, optional):polymarket|kalshi|manifold|metaculuslimit(number, optional)maxCandidates(number, optional)minScore(number, optional)platformWeights(JSON string, optional)
Response:
{
"results": [
{
"score": 0.8421,
"market": {
"platform": "polymarket",
"id": "123",
"slug": "will-x-happen",
"question": "...",
"description": "...",
"url": "...",
"status": "open",
"endDate": "2026-01-01T00:00:00.000Z",
"resolved": false,
"volume24h": 1234,
"liquidity": 5678,
"openInterest": 910,
"predictions": 42
}
}
]
}
Market index stats (requires marketIndex.enabled).
Query parameters:
platforms(comma-separated list, optional)
Trigger a manual market index sync (requires marketIndex.enabled).
Body (JSON):
platforms(array or comma-separated string, optional)limitPerPlatform(number, optional)status(open|closed|settled|all, optional)excludeSports(boolean, optional)minVolume24h(number, optional)minLiquidity(number, optional)minOpenInterest(number, optional)minPredictions(number, optional)excludeResolved(boolean, optional)prune(boolean, optional)staleAfterMs(number, optional)
Response:
{ "result": { "indexed": 123, "byPlatform": { "polymarket": 100 } } }
Get historical tick data (requires tickRecorder.enabled).
Query parameters:
outcomeId(string, optional): filter by outcomestartTime(number, optional): Unix timestamp in ms (default: 24h ago)endTime(number, optional): Unix timestamp in ms (default: now)limit(number, optional): max results (default: 1000)
Response:
{
"ticks": [
{
"time": "2026-02-02T12:00:00.000Z",
"platform": "polymarket",
"marketId": "0x123",
"outcomeId": "yes",
"price": 0.55,
"prevPrice": 0.54
}
]
}Get OHLC candle data (requires tickRecorder.enabled).
Query parameters:
outcomeId(string, required): outcome IDinterval(string, optional):1m|5m|15m|1h|4h|1d(default:1h)startTime(number, optional): Unix timestamp in ms (default: 7d ago)endTime(number, optional): Unix timestamp in ms (default: now)
Response:
{
"candles": [
{
"time": 1706500000000,
"open": 0.50,
"high": 0.56,
"low": 0.49,
"close": 0.55,
"tickCount": 42
}
]
}Get historical orderbook snapshots (requires tickRecorder.enabled).
Query parameters:
outcomeId(string, optional): filter by outcomestartTime(number, optional): Unix timestamp in ms (default: 1h ago)endTime(number, optional): Unix timestamp in ms (default: now)limit(number, optional): max results (default: 100)
Response:
{
"snapshots": [
{
"time": "2026-02-02T12:00:00.000Z",
"platform": "polymarket",
"marketId": "0x123",
"outcomeId": "yes",
"bids": [[0.54, 1000], [0.53, 500]],
"asks": [[0.56, 800], [0.57, 1200]],
"spread": 0.02,
"midPrice": 0.55
}
]
}Get tick recorder statistics (requires tickRecorder.enabled).
Response:
{
"stats": {
"ticksRecorded": 150000,
"orderbooksRecorded": 50000,
"ticksInBuffer": 45,
"orderbooksInBuffer": 12,
"lastFlushTime": 1706500000000,
"dbConnected": true,
"platforms": ["polymarket", "kalshi"]
}
}Get tick streamer statistics.
Response:
{
"stats": {
"connectedClients": 5,
"totalSubscriptions": 12,
"ticksBroadcast": 45000,
"orderbooksBroadcast": 15000,
"uptime": 3600000
}
}Get computed trading features for a specific market.
Query parameters:
outcomeId(string, optional): specific outcome
Response:
{
"features": {
"timestamp": 1706500000000,
"platform": "polymarket",
"marketId": "0x123",
"outcomeId": "yes",
"tick": {
"price": 0.55,
"priceChange": 0.01,
"priceChangePct": 1.85,
"momentum": 0.03,
"velocity": 0.001,
"volatility": 0.015,
"volatilityPct": 1.5,
"tickCount": 150,
"tickIntensity": 2.5,
"vwap": null
},
"orderbook": {
"spread": 0.02,
"spreadPct": 3.6,
"midPrice": 0.55,
"bidDepth": 5000,
"askDepth": 4500,
"totalDepth": 9500,
"imbalance": 0.053,
"imbalanceRatio": 1.11,
"bestBid": 0.54,
"bestAsk": 0.56,
"bestBidSize": 1000,
"bestAskSize": 800,
"weightedBidPrice": 0.535,
"weightedAskPrice": 0.565,
"bidDepthAt1Pct": 2000,
"askDepthAt1Pct": 1800,
"bidDepthAt5Pct": 4500,
"askDepthAt5Pct": 4000
},
"signals": {
"buyPressure": 0.62,
"sellPressure": 0.38,
"trendStrength": 0.15,
"liquidityScore": 0.72
}
}
}Get all computed features for all tracked markets.
Response:
{
"snapshots": [
{
"timestamp": 1706500000000,
"platform": "polymarket",
"marketId": "0x123",
"outcomeId": "yes",
"features": { ... }
}
],
"count": 15
}Get feature engineering service statistics.
Response:
{
"stats": {
"marketsTracked": 15,
"ticksProcessed": 45000,
"orderbooksProcessed": 12000
}
}Development WebSocket endpoint. Currently echoes incoming JSON with a wrapper:
{ "type": "res", "id": "<client id>", "ok": true, "payload": { "echo": <message> } }
Real-time tick data streaming via WebSocket. Subscribe to specific markets and receive live price/orderbook updates.
Client messages:
// Subscribe to a market (ticks enabled by default, orderbook opt-in)
{ "type": "subscribe", "platform": "polymarket", "marketId": "0x123", "ticks": true, "orderbook": true }
// Unsubscribe
{ "type": "unsubscribe", "platform": "polymarket", "marketId": "0x123" }
// Ping (keepalive)
{ "type": "ping" }Server messages:
// Subscription confirmed
{ "type": "subscribed", "platform": "polymarket", "marketId": "0x123", "ticks": true, "orderbook": true }
// Price tick
{ "type": "tick", "platform": "polymarket", "marketId": "0x123", "outcomeId": "yes", "price": 0.55, "prevPrice": 0.54, "timestamp": 1706500000000 }
// Orderbook update
{ "type": "orderbook", "platform": "polymarket", "marketId": "0x123", "outcomeId": "yes", "bids": [[0.54, 1000]], "asks": [[0.56, 800]], "spread": 0.02, "midPrice": 0.55, "timestamp": 1706500000000 }
// Pong (keepalive response)
{ "type": "pong", "timestamp": 1706500000000 }
// Error
{ "type": "error", "message": "Max subscriptions reached", "code": "MAX_SUBSCRIPTIONS" }Example usage (JavaScript):
const ws = new WebSocket('ws://localhost:18789/api/ticks/stream');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'subscribe',
platform: 'polymarket',
marketId: '0x123abc',
ticks: true,
orderbook: true
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'tick') {
console.log(`Price: ${msg.price}, Change: ${msg.price - msg.prevPrice}`);
} else if (msg.type === 'orderbook') {
console.log(`Spread: ${msg.spread}, Mid: ${msg.midPrice}`);
}
};WebChat WebSocket endpoint used by /webchat.
Client messages:
auth:{ "type": "auth", "token": "<WEBCHAT_TOKEN>", "userId": "web-123" }message:{ "type": "message", "text": "hi", "attachments": [] }edit:{ "type": "edit", "messageId": "<id>", "text": "new text" }delete:{ "type": "delete", "messageId": "<id>" }
Server messages:
connected,authenticated,ack,message,edit,delete,error
Attachment fields (if provided):
type:image|video|audio|document|voice|stickerurlordata(base64)mimeType,filename,size,width,height,duration,caption
Session management and message history for WebChat.
GET /api/chat/sessions?userId=<id>— list sessions (returns id, title, updatedAt, messageCount, lastMessage)GET /api/chat/sessions/:id— load session with messages (supports?limit=N&before=timestampfor pagination)POST /api/chat/sessions— create new session ({ "userId": "web-123" })PATCH /api/chat/sessions/:id— rename session ({ "title": "New title" })DELETE /api/chat/sessions/:id— delete session and all its messages
Messages are stored in a dedicated messages table (one row per message, append-only). Chat history is unlimited — the LLM receives the last 20 messages plus a compressed summary of earlier conversation for context continuity.
The lightweight Clodds Worker (apps/clodds-worker) exposes a separate REST API on Cloudflare's edge network.
https://clodds-worker.<account>.workers.dev
Health check with service status.
Response:
{
"status": "ok",
"version": "0.3.10",
"timestamp": "2026-01-29T...",
"services": {
"telegram": true,
"discord": false,
"slack": false,
"kalshi": true,
"anthropic": true
}
}Search markets across platforms.
Query parameters:
qorquery(string, required): search textplatform(string, optional):polymarket|kalshi|manifoldlimit(number, optional, max 50)
Response:
{
"markets": [
{
"id": "...",
"platform": "polymarket",
"question": "Will X happen?",
"outcomes": [{ "id": "...", "name": "Yes", "price": 0.45 }],
"volume24h": 12345,
"url": "https://polymarket.com/..."
}
],
"count": 10
}Get a specific market by platform and ID.
Response:
{ "market": { ... } }Get orderbook for a market (Polymarket, Kalshi only).
Response:
{
"orderbook": {
"platform": "polymarket",
"marketId": "...",
"bids": [[0.45, 1000], [0.44, 500]],
"asks": [[0.46, 800], [0.47, 1200]],
"spread": 0.01,
"midPrice": 0.455,
"timestamp": 1706500000000
}
}Scan for arbitrage opportunities.
Query parameters:
min_edge(number, optional): minimum edge % (default 1)platforms(string, optional): comma-separated listlimit(number, optional, max 50)
Response:
{
"opportunities": [
{
"id": "polymarket-abc123",
"platform": "polymarket",
"marketId": "abc123",
"marketQuestion": "Will X?",
"yesPrice": 0.48,
"noPrice": 0.49,
"edgePct": 0.03,
"mode": "internal",
"foundAt": 1706500000000
}
],
"count": 5,
"scannedPlatforms": ["polymarket", "kalshi"],
"minEdge": 1
}Get recently found arbitrage opportunities from database.
Query parameters:
limit(number, optional, max 100)
POST /webhook/telegram- Telegram Bot API webhookPOST /webhook/discord- Discord Interactions endpointPOST /webhook/slack- Slack Events API endpoint
See apps/clodds-worker/README.md for webhook setup instructions.
The following modules can be imported and used directly in your TypeScript/JavaScript code.
import { executeUniswapSwap, getUniswapQuote, executeOneInchSwap, compareDexRoutes } from 'clodds/evm';
// Get quote from Uniswap V3
const quote = await getUniswapQuote({
chain: 'ethereum', // 'ethereum' | 'arbitrum' | 'optimism' | 'base' | 'polygon'
inputToken: 'USDC',
outputToken: 'WETH',
amount: '1000',
slippageBps: 50,
});
// Execute swap with MEV protection
const result = await executeUniswapSwap({
chain: 'ethereum',
inputToken: 'USDC',
outputToken: 'WETH',
amount: '1000',
});
// Compare Uniswap vs 1inch for best route
const comparison = await compareDexRoutes({
chain: 'ethereum',
fromToken: 'USDC',
toToken: 'WETH',
amount: '1000',
});
console.log(`Best route: ${comparison.best}, saves ${comparison.savings}`);import { createMevProtectionService, sendFlashbotsProtect, submitJitoBundle } from 'clodds/execution/mev-protection';
// Create protection service
const mev = createMevProtectionService({
level: 'aggressive', // 'none' | 'basic' | 'aggressive'
maxPriceImpact: 3,
jitoTipLamports: 10000,
});
// Send EVM transaction via Flashbots Protect
const result = await mev.sendEvmTransaction('ethereum', signedTx);
// Submit Solana bundle via Jito
const bundle = await mev.createSolanaBundle(transactions, payerPubkey);
await mev.submitSolanaBundle(bundle);import { createWhaleTracker, getMarketWhaleActivity } from 'clodds/feeds/polymarket/whale-tracker';
const tracker = createWhaleTracker({
minTradeSize: 10000, // $10k minimum
minPositionSize: 50000, // $50k to track
enableRealtime: true,
});
tracker.on('trade', (trade) => {
console.log(`Whale ${trade.side} $${trade.usdValue} on ${trade.marketQuestion}`);
});
tracker.on('positionOpened', (position) => {
console.log(`New position: ${position.address} - $${position.usdValue}`);
});
await tracker.start();
// Get whale activity for a specific market
const activity = await getMarketWhaleActivity(marketId);
console.log(`Buy volume: $${activity.buyVolume}, Sell volume: $${activity.sellVolume}`);import { createCryptoWhaleTracker } from 'clodds/feeds/crypto/whale-tracker';
const tracker = createCryptoWhaleTracker({
chains: ['solana', 'ethereum', 'polygon', 'arbitrum', 'base', 'optimism'],
thresholds: {
solana: 10000, // $10k+ on Solana
ethereum: 50000, // $50k+ on ETH
polygon: 5000, // $5k+ on Polygon
arbitrum: 10000,
base: 10000,
optimism: 10000,
},
birdeyeApiKey: process.env.BIRDEYE_API_KEY, // For Solana
alchemyApiKey: process.env.ALCHEMY_API_KEY, // For EVM chains
});
// Real-time transaction events
tracker.on('transaction', (tx) => {
console.log(`${tx.chain}: ${tx.type} $${tx.usdValue} from ${tx.wallet}`);
console.log(` Token: ${tx.token}, Amount: ${tx.amount}`);
});
// Whale alerts (above threshold)
tracker.on('alert', (alert) => {
console.log(`WHALE ALERT: ${alert.message}`);
});
// Watch specific wallets
tracker.watchWallet('solana', 'ABC123...', { label: 'Known Whale' });
tracker.watchWallet('ethereum', '0x1234...', { label: 'Smart Money' });
await tracker.start();
// Query methods
const topSolWhales = tracker.getTopWhales('solana', 10);
const recentEthTxs = tracker.getRecentTransactions('ethereum', 100);
const wallet = tracker.getWallet('solana', 'ABC123...');Supported Chains:
| Chain | Provider | Features |
|---|---|---|
| Solana | Birdeye WebSocket | Token transfers, swaps, NFTs |
| Ethereum | Alchemy WebSocket | ERC-20, ETH transfers |
| Polygon | Alchemy WebSocket | MATIC, tokens |
| Arbitrum | Alchemy WebSocket | L2 activity |
| Base | Alchemy WebSocket | Coinbase L2 |
| Optimism | Alchemy WebSocket | OP ecosystem |
Transaction Types: transfer, swap, nft, stake, unknown
import { createCopyTradingService, findBestAddressesToCopy } from 'clodds/trading/copy-trading';
// Find profitable addresses to copy
const topTraders = await findBestAddressesToCopy(whaleTracker, {
minWinRate: 55,
minTrades: 10,
minAvgReturn: 5,
});
const copyTrader = createCopyTradingService(whaleTracker, execution, {
followedAddresses: topTraders.map(t => t.address),
sizingMode: 'fixed', // 'fixed' | 'proportional' | 'percentage'
fixedSize: 100, // $100 per trade
maxPositionSize: 500, // Max $500 per market
copyDelayMs: 5000, // 5s delay before copying
dryRun: true, // Start in dry run mode
// Stop-loss / Take-profit monitoring
stopLossPct: 10, // Exit at 10% loss
takeProfitPct: 20, // Exit at 20% profit
});
copyTrader.on('tradeCopied', (trade) => {
console.log(`Copied: ${trade.side} ${trade.size} @ ${trade.entryPrice}`);
});
// SL/TP events
copyTrader.on('positionClosed', (trade, reason) => {
console.log(`Position closed: ${reason} at ${trade.exitPrice}`);
// reason: 'stop_loss' | 'take_profit' | 'manual'
});
copyTrader.start();
// Follow/unfollow addresses dynamically
copyTrader.follow('0x...');
copyTrader.unfollow('0x...');SL/TP Monitoring:
- 5-second price polling interval
- Automatic position exit when thresholds hit
- Events emitted for position closures with reason
import { createSmartRouter, quickPriceCompare } from 'clodds/execution/smart-router';
const router = createSmartRouter(feeds, {
mode: 'balanced', // 'best_price' | 'best_liquidity' | 'lowest_fee' | 'balanced'
enabledPlatforms: ['polymarket', 'kalshi'],
maxSlippage: 1,
preferMaker: true,
allowSplitting: true,
});
// Find best route for an order
const result = await router.findBestRoute({
marketId: 'trump-win-2024',
side: 'buy',
size: 1000,
limitPrice: 0.52,
});
console.log(`Best platform: ${result.bestRoute.platform}`);
console.log(`Net price: ${result.bestRoute.netPrice}`);
console.log(`Savings: $${result.totalSavings}`);
// Quick price comparison
const prices = await quickPriceCompare(feeds, 'trump-win-2024');
console.log(prices); // { polymarket: 0.52, kalshi: 0.54 }import {
OAuthClient,
interactiveOAuth,
createAnthropicOAuth,
createOpenAIOAuth,
createGoogleOAuth
} from 'clodds/auth/oauth';
import { CopilotAuthClient, interactiveCopilotAuth } from 'clodds/auth/copilot';
import { GoogleAuthClient, GeminiClient, interactiveGoogleAuth } from 'clodds/auth/google';
import { QwenAuthClient, QwenClient } from 'clodds/auth/qwen';
// OAuth for Anthropic/OpenAI
const anthropicOAuth = createAnthropicOAuth('client-id', 'client-secret');
const tokens = await interactiveOAuth({
provider: 'anthropic',
clientId: 'your-client-id',
scopes: ['api:read', 'api:write'],
});
// GitHub Copilot authentication
const copilotAuth = new CopilotAuthClient();
await interactiveCopilotAuth(); // Interactive device code flow
const headers = await copilotAuth.getHeaders();
// Google/Gemini authentication
const googleAuth = new GoogleAuthClient({ projectId: 'my-project' });
await interactiveGoogleAuth();
const gemini = new GeminiClient({ projectId: 'my-project' });
const response = await gemini.generateContent('gemini-pro', 'Hello world');
// Qwen/DashScope authentication
const qwen = new QwenClient({ apiKey: process.env.DASHSCOPE_API_KEY });
const result = await qwen.generate('qwen-turbo', 'Hello');import {
initTelemetry,
TelemetryService,
LLMInstrumentation,
createLLMInstrumentation
} from 'clodds/telemetry';
// Initialize telemetry
const telemetry = initTelemetry({
enabled: true,
serviceName: 'clodds',
otlpEndpoint: 'http://localhost:4318', // OTLP collector
jaegerEndpoint: 'http://localhost:14268', // Jaeger
metricsPort: 9090, // Prometheus metrics
sampleRate: 1.0,
});
// Create LLM instrumentation
const llmInstr = createLLMInstrumentation();
// Trace LLM completion
const { result, span } = await llmInstr.traceCompletion(
'anthropic',
'claude-3-5-sonnet',
() => provider.complete({ model, messages }),
{ inputTokens: 100, userId: 'user-123' }
);
// Record token usage
llmInstr.recordTokenUsage('anthropic', 'claude-3-5-sonnet', 100, 500);
// Manual tracing
const span = telemetry.startTrace('my-operation', { custom: 'attr' });
telemetry.addEvent(span, 'checkpoint');
telemetry.endSpan(span, 'ok');
// Metrics
telemetry.recordCounter('requests_total', 1, { endpoint: '/api' });
telemetry.recordHistogram('request_duration_ms', 150);
// Start Prometheus metrics server
telemetry.startMetricsServer(9090);import { createTaskRunner, TaskRunner, TaskDefinition } from 'clodds/extensions/task-runner';
const runner = createTaskRunner({
maxConcurrent: 4,
defaultTimeout: 60000,
planningModel: 'claude-3-5-sonnet',
}, provider);
// Plan tasks from high-level goal
const tasks = await runner.planTasks('Build a REST API with user authentication');
// Execute tasks with dependency resolution
const results = await runner.executeTasks(tasks, '/path/to/workdir');
// Built-in executors: shell, file, http, llm, transform
const shellTask: TaskDefinition = {
id: 'build',
name: 'Build project',
type: 'atomic',
executor: 'shell',
input: { command: 'npm', args: ['run', 'build'] },
};
// Register custom executor
runner.registerExecutor({
name: 'custom',
execute: async (task, context) => {
// Custom logic
return { success: true };
},
});import { createOpenProseExtension } from 'clodds/extensions/open-prose';
const prose = await createOpenProseExtension({
enabled: true,
enableHistory: true,
maxHistoryEntries: 100,
});
// Create and edit documents
const doc = await prose.createDocument('My Article', '# Draft\n\nContent here...', 'markdown');
await prose.updateDocument(doc.id, '# Updated\n\nNew content', 'Major revision');
// AI-assisted editing (requires provider)
const { document, changes } = await prose.aiEdit(doc.id, 'Make it more concise', provider);
const completion = await prose.aiComplete(doc.id, 50, provider);
const summary = await prose.aiSummarize(doc.id, provider);
const { document: rewritten } = await prose.aiRewrite(doc.id, 'formal', provider);
// Version history
const history = await prose.getHistory(doc.id);
await prose.restoreVersion(doc.id, 3);
// Export
const html = await prose.exportDocument(doc.id, 'html');import { createOpportunityExecutor } from 'clodds/opportunity/executor';
const executor = createOpportunityExecutor(finder, execution, {
minEdge: 1.0, // Minimum 1% edge
minLiquidity: 500, // Minimum $500 liquidity
maxPositionSize: 100, // Max $100 per trade
maxDailyLoss: 500, // Stop after $500 daily loss
maxConcurrentPositions: 3,
preferMakerOrders: true,
dryRun: true, // Start in dry run mode
});
executor.on('executed', (opp, result) => {
console.log(`Executed: ${opp.id}, profit: $${result.actualProfit}`);
});
executor.on('skipped', (opp, reason) => {
console.log(`Skipped: ${reason}`);
});
executor.start();
// View stats
const stats = executor.getStats();
console.log(`Win rate: ${stats.winRate}%, Total P&L: $${stats.totalProfit - stats.totalLoss}`);import {
getFedWatchProbabilities,
get538Probability,
getRCPPollingAverage,
analyzeEdge,
calculateKelly
} from 'clodds/feeds/external';
// Get Fed rate probabilities
const fedWatch = await getFedWatchProbabilities();
console.log(fedWatch.get('January 2026')); // 0.85
// Get election model probability
const model = await get538Probability('Trump president');
console.log(model?.probability); // 0.52
// Get polling average
const polls = await getRCPPollingAverage('Trump vs Biden');
console.log(polls?.probability); // 0.48
// Analyze edge vs market price
const edge = await analyzeEdge(
'market-123',
'Will Trump win?',
0.45, // market price
'politics'
);
console.log(`Fair value: ${edge.fairValue}, Edge: ${edge.edgePct}%`);
// Calculate Kelly bet size
const kelly = calculateKelly(0.45, 0.52, 10000);
console.log(`Half Kelly: $${kelly.halfKelly}`);On-chain Solana perpetual futures via Percolator protocol. Requires PERCOLATOR_ENABLED=true.
Get current market state (oracle price, open interest, funding rate, spread).
Response:
{
"oraclePrice": 142.50,
"totalOpenInterest": 1250000,
"vault": 5000000,
"insuranceFund": 250000,
"fundingRate": 3,
"bestBid": { "lpIndex": 0, "priceUsd": 142.29 },
"bestAsk": { "lpIndex": 0, "priceUsd": 142.71 },
"spreadBps": 29.5,
"lastCrankSlot": 298456123
}Get user's open Percolator positions.
Response:
{
"positions": [
{
"accountIndex": 5,
"side": "LONG",
"size": 100.00,
"entryPrice": 140.50,
"capital": 500.00,
"pnl": 14.28
}
]
}Execute a Percolator trade (long/short).
Request:
{
"direction": "long",
"size": 100
}Response:
{
"success": true,
"signature": "5UxM...",
"slot": 298456200
}Deposit USDC collateral.
Request: { "amount": 500 }
Withdraw USDC collateral.
Request: { "amount": 100 }
Code scanning, address safety checks, and transaction validation. Always available (no env vars required).
Scan code or plugin for malicious patterns.
Request:
{
"code": "const x = require('child_process').exec(userInput);"
}Response:
{
"riskScore": 85,
"findings": [
{ "category": "shell_exec", "severity": "critical", "pattern": "child_process.exec with user input" }
],
"entropy": 4.2
}Check address safety (auto-detects Solana/EVM).
Request: { "address": "0x..." }
Response:
{
"safe": false,
"chain": "ethereum",
"flags": ["known_drainer", "inferno_drainer"],
"riskLevel": "critical"
}Pre-flight transaction validation.
Request:
{
"destination": "0x...",
"amount": 1000,
"token": "USDC"
}Scanner statistics (total scans, threats blocked, scam DB size).
GoPlus-powered token security analysis.
Audit a token contract. Auto-detects chain (base58 = Solana, 0x = EVM).
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
chain |
string | No | Override chain: ethereum, bsc, polygon, arbitrum, base, solana, etc. |
Response:
{
"address": "0x...",
"chain": "ethereum",
"riskScore": 35,
"flags": {
"isHoneypot": false,
"hasMintFunction": true,
"hasBlacklist": false,
"isProxy": false,
"topHolderConcentration": 0.42
},
"liquidity": 1250000,
"holders": 5420
}Quick boolean safety check. Returns { "address": "...", "chain": "...", "safe": true }.
Dollar-cost averaging across 16 platforms.
List active DCA orders.
Response:
{
"orders": [
{
"id": "dca_abc123",
"platform": "polymarket",
"status": "active",
"totalAmount": 1000,
"amountPerCycle": 50,
"intervalSec": 3600,
"cyclesCompleted": 8,
"cyclesRemaining": 12,
"totalSpent": 400,
"createdAt": 1706500000000
}
]
}Get a single DCA order by ID.
Create a new DCA order.
Request:
{
"platform": "polymarket",
"tokenId": "0x...",
"totalAmount": 1000,
"amountPerCycle": 50,
"intervalSec": 3600,
"price": 0.55,
"side": "buy"
}Pause a running DCA order.
Resume a paused DCA order.
Cancel a DCA order.
All endpoints require auth. Prefix: /api/twap.
| Method | Path | Description |
|---|---|---|
| GET | /api/twap/orders | List all TWAP orders |
| GET | /api/twap/:id | Get specific TWAP order |
| POST | /api/twap/create | Create TWAP order |
| POST | /api/twap/:id/pause | Pause a TWAP order |
| POST | /api/twap/:id/resume | Resume a TWAP order |
| DELETE | /api/twap/:id | Cancel a TWAP order |
| Method | Path | Description |
|---|---|---|
| GET | /api/bracket/orders | List all bracket orders |
| GET | /api/bracket/:id | Get specific bracket order |
| POST | /api/bracket/create | Create bracket order (entry + TP + SL) |
| POST | /api/bracket/:id/cancel | Cancel bracket order |
| GET | /api/bracket/stats | Get bracket statistics |
| Method | Path | Description |
|---|---|---|
| GET | /api/triggers/orders | List all trigger orders |
| GET | /api/triggers/:id | Get specific trigger order |
| POST | /api/triggers/create | Create trigger order |
| DELETE | /api/triggers/:id | Cancel trigger order |
| POST | /api/triggers/:id/pause | Pause trigger order |
| POST | /api/triggers/:id/resume | Resume trigger order |
| Method | Path | Description |
|---|---|---|
| GET | /api/copy-trading/leaders | List tracked leaders |
| POST | /api/copy-trading/leaders | Add leader wallet |
| DELETE | /api/copy-trading/leaders/:address | Remove leader |
| GET | /api/copy-trading/positions | List copied positions |
| GET | /api/copy-trading/leaders/:address/positions | Leader's positions |
| GET | /api/copy-trading/leaders/:address/stats | Leader performance |
| POST | /api/copy-trading/start | Start copy trading |
| POST | /api/copy-trading/stop | Stop copy trading |
| GET | /api/copy-trading/status | Service status |
| GET | /api/copy-trading/stats | Aggregate stats |
| PUT | /api/copy-trading/config | Update config |
| Method | Path | Description |
|---|---|---|
| GET | /api/opportunities | List opportunities |
| GET | /api/opportunities/:id | Get specific opportunity |
| GET | /api/opportunities/history | Past opportunities |
| GET | /api/opportunities/stats | Finder statistics |
| GET | /api/opportunities/linked-markets | Linked markets |
| POST | /api/opportunities/scan | Manual scan |
| POST | /api/opportunities/start | Start scanning |
| POST | /api/opportunities/stop | Stop scanning |
| PUT | /api/opportunities/config | Update config |
| GET | /api/opportunities/platforms | Available platforms |
| POST | /api/opportunities/:id/execute | Execute opportunity |
| POST | /api/opportunities/:id/simulate | Simulate execution |
| GET | /api/opportunities/executions | Execution results |
| POST | /api/opportunities/auto-execute/start | Start auto-execute |
| Method | Path | Description |
|---|---|---|
| GET | /api/whales/wallets | List tracked wallets |
| POST | /api/whales/wallets | Add wallet |
| DELETE | /api/whales/wallets/:address | Remove wallet |
| GET | /api/whales/:address/positions | Wallet positions |
| GET | /api/whales/:address/history | Wallet history |
| POST | /api/whales/:address/record-close | Record closed position |
| GET | /api/whales/stats | Tracker statistics |
| GET | /api/whales/leaderboard | Performance leaderboard |
| POST | /api/whales/start | Start tracking |
| POST | /api/whales/stop | Stop tracking |
| GET | /api/whales/status | Service status |
| PUT | /api/whales/config | Update config |
| GET | /api/whales/activity | Recent activity |
| Method | Path | Description |
|---|---|---|
| POST | /api/risk/assess | Assess trade risk |
| GET | /api/risk/limits/:userId | Get user risk limits |
| PUT | /api/risk/limits/:userId | Update user limits |
| POST | /api/risk/pnl | Record PnL entry |
| GET | /api/risk/report/:userId | Full risk report |
| GET | /api/risk/stats | Engine statistics |
| Method | Path | Description |
|---|---|---|
| POST | /api/routing/quote | Find best route |
| POST | /api/routing/quotes | Get all quotes |
| POST | /api/routing/compare | Compare routes |
| PUT | /api/routing/config | Update config |
| Method | Path | Description |
|---|---|---|
| GET | /api/feeds/cache-stats | Cache statistics |
| POST | /api/feeds/cache/clear | Clear cache |
| GET | /api/feeds/search | Search markets |
| GET | /api/feeds/news | Latest news |
| GET | /api/feeds/news/search | Search news |
| GET | /api/feeds/market/:marketId | Market data |
| GET | /api/feeds/price/:platform/:marketId | Current price |
| GET | /api/feeds/orderbook/:platform/:marketId | Orderbook |
| POST | /api/feeds/analyze-edge | Analyze edge |
| POST | /api/feeds/kelly | Kelly criterion |
| Method | Path | Description |
|---|---|---|
| GET | /api/monitoring/health | System health |
| GET | /api/monitoring/providers | Provider health |
| GET | /api/monitoring/process | Process info |
| Method | Path | Description |
|---|---|---|
| GET | /api/alt-data/signals | Recent signals |
| GET | /api/alt-data/sentiment/:marketId | Market sentiment |
| GET | /api/alt-data/stats | Service stats |
| Method | Path | Description |
|---|---|---|
| GET | /api/alerts | List alerts |
| GET | /api/alerts/:id | Get alert |
| POST | /api/alerts/price | Create price alert |
| POST | /api/alerts/price-change | Create price-change alert |
| POST | /api/alerts/volume | Create volume alert |
| PUT | /api/alerts/:id/enable | Enable alert |
| PUT | /api/alerts/:id/disable | Disable alert |
| DELETE | /api/alerts/:id | Delete alert |
| POST | /api/alerts/start-monitoring | Start monitoring |
| POST | /api/alerts/stop-monitoring | Stop monitoring |
| Method | Path | Description |
|---|---|---|
| GET | /api/queue/jobs/:id | Job status |
| POST | /api/queue/jobs/:id/wait | Wait for job |
| Method | Path | Description |
|---|---|---|
| GET | /api/webhooks | List webhooks |
| GET | /api/webhooks/:id | Get webhook |
| PUT | /api/webhooks/:id/enable | Enable webhook |
| PUT | /api/webhooks/:id/disable | Disable webhook |
| DELETE | /api/webhooks/:id | Delete webhook |
| POST | /api/webhooks/:id/regenerate-secret | Regenerate secret |
| Method | Path | Description |
|---|---|---|
| GET | /api/payments/status | Payment configuration status |
| GET | /api/payments/history | Payment history |
| GET | /api/payments/balance/:network | Network balance |
| GET | /api/payments/address/:network | Wallet address |
| Method | Path | Description |
|---|---|---|
| POST | /api/embeddings/embed | Embed single text |
| POST | /api/embeddings/embed-batch | Embed multiple texts |
| POST | /api/embeddings/similarity | Cosine similarity |
| POST | /api/embeddings/search | Semantic search |
| POST | /api/embeddings/cache/clear | Clear cache |
| Method | Path | Description |
|---|---|---|
| GET | /api/cron/status | Service status |
| GET | /api/cron/jobs | List jobs |
| GET | /api/cron/jobs/:id | Get job |
| POST | /api/cron/jobs | Create job |
| PATCH | /api/cron/jobs/:id | Update job |
| DELETE | /api/cron/jobs/:id | Remove job |
| POST | /api/cron/jobs/:id/run | Run job immediately |
| Method | Path | Description |
|---|---|---|
| GET | /api/positions/managed | List managed positions + stats |
| GET | /api/positions/managed/:id | Get position |
| GET | /api/positions/managed/by-platform/:platform | Positions by platform |
| POST | /api/positions/managed | Create/update position |
| POST | /api/positions/managed/:id/close | Close position |
| POST | /api/positions/managed/:id/stop-loss | Set stop-loss |
| POST | /api/positions/managed/:id/take-profit | Set take-profit |
| DELETE | /api/positions/managed/:id/stop-loss | Remove stop-loss |
| DELETE | /api/positions/managed/:id/take-profit | Remove take-profit |
| PUT | /api/positions/managed/:id/price | Update price |
| PUT | /api/positions/managed/prices | Batch update prices |
| POST | /api/positions/managed/start | Start monitoring |
| POST | /api/positions/managed/stop | Stop monitoring |
The Compute API allows agents to pay for compute resources with USDC. No API keys needed - just a wallet.
https://api.cloddsbot.com
No API keys required. Agents authenticate by:
- Depositing USDC to the treasury wallet on any supported network
- Including payment proof in requests
Treasury wallet: Set via CLODDS_TREASURY_WALLET env var on the server.
Supported networks: Base, Ethereum, Polygon (USDC)
- Per-wallet: 60 requests/minute
- Per-IP: 100 requests/minute
Rate limit headers are included in responses:
X-RateLimit-Remaining: Remaining requests in windowRetry-After: Seconds to wait (when rate limited)
Health check and service info.
Response:
{
"status": "ok",
"service": "clodds-compute",
"version": "v1",
"uptime": 123456,
"activeJobs": 2
}Get pricing for all compute services.
Response:
{
"llm": {
"service": "llm",
"basePrice": 0,
"unit": "token",
"pricePerUnit": 0.000003,
"minCharge": 0.001,
"maxCharge": 10
},
"code": {
"service": "code",
"basePrice": 0.01,
"unit": "second",
"pricePerUnit": 0.001,
"minCharge": 0.01,
"maxCharge": 1
},
"web": {
"service": "web",
"basePrice": 0.005,
"unit": "request",
"pricePerUnit": 0.005,
"minCharge": 0.005,
"maxCharge": 0.1
},
"trade": {
"service": "trade",
"basePrice": 0.01,
"unit": "call",
"pricePerUnit": 0.01,
"minCharge": 0.01,
"maxCharge": 0.5
},
"data": {
"service": "data",
"basePrice": 0.001,
"unit": "request",
"pricePerUnit": 0.001,
"minCharge": 0.001,
"maxCharge": 0.1
},
"storage": {
"service": "storage",
"basePrice": 0,
"unit": "mb",
"pricePerUnit": 0.0001,
"minCharge": 0.001,
"maxCharge": 1
},
"gpu": {
"service": "gpu",
"basePrice": 0,
"unit": "second",
"pricePerUnit": 0.01,
"minCharge": 0.1,
"maxCharge": 100
},
"ml": {
"service": "ml",
"basePrice": 0.01,
"unit": "request",
"pricePerUnit": 0.01,
"minCharge": 0.01,
"maxCharge": 1
}
}Get API metrics and statistics.
Response:
{
"uptime": 123456,
"totalRequests": 1500,
"totalRevenue": 45.50,
"activeJobs": 2,
"jobsByStatus": {
"pending": 1,
"processing": 1,
"completed": 1450,
"failed": 48
},
"requestsByService": {
"llm": 1200,
"code": 200,
"web": 100
}
}Check wallet balance.
Response:
{
"wallet": "0x...",
"available": 10.50,
"pending": 0.25,
"totalDeposited": 15.00,
"totalSpent": 4.25
}Deposit credits to a wallet.
Request body:
{
"wallet": "0x...",
"paymentProof": {
"txHash": "0x...",
"network": "base",
"amountUsd": 10.00,
"token": "USDC",
"timestamp": 1706500000000
}
}Response:
{
"success": true,
"credits": 10.00,
"txHash": "0x..."
}Get usage statistics for a wallet.
Query parameters:
period(optional):day,week,month, orall(default:all)
Response:
{
"wallet": "0x...",
"period": "week",
"byService": {
"llm": {
"requests": 50,
"cost": 2.50,
"avgDuration": 1500
},
"code": {
"requests": 10,
"cost": 0.50,
"avgDuration": 3000
}
},
"totalCost": 3.00,
"totalRequests": 60
}List jobs for a wallet.
Query parameters:
limit(optional): Max results (default: 50, max: 100)
Response:
{
"jobs": [
{
"id": "req_123",
"jobId": "job_456",
"service": "llm",
"status": "completed",
"cost": 0.05,
"timestamp": 1706500000000
}
],
"count": 1
}Get status of an async compute job.
Headers:
X-Wallet-Address(optional): Wallet address for ownership verification
Response:
{
"id": "req_123",
"jobId": "job_456",
"service": "llm",
"status": "completed",
"result": {
"content": "The weather is sunny.",
"model": "claude-opus-4-6",
"usage": { "inputTokens": 10, "outputTokens": 5 },
"stopReason": "end_turn"
},
"cost": 0.05,
"usage": {
"units": 1500,
"unitType": "token",
"durationMs": 2300,
"breakdown": {
"base": 0,
"usage": 0.0045,
"total": 0.0045
}
},
"timestamp": 1706500000000
}Status values: pending, processing, completed, failed
Cancel a pending job and refund the reserved balance.
Headers:
X-Wallet-Address(required): Wallet address for ownership verification
Response:
{
"success": true,
"jobId": "job_456"
}Note: Only pending jobs can be cancelled. Processing/completed jobs cannot be cancelled.
Submit a compute request. Replace :service with: llm, code, web, trade, data, storage, gpu, ml, or security.
Request body:
{
"wallet": "0x...",
"payload": { ... },
"paymentProof": {
"txHash": "0x...",
"network": "base",
"amountUsd": 10.00,
"token": "USDC",
"timestamp": 1706500000000
},
"callbackUrl": "https://your-server.com/webhook"
}Response:
{
"id": "req_123",
"jobId": "job_456",
"service": "llm",
"status": "pending",
"cost": 0.05,
"timestamp": 1706500000000
}{
"wallet": "0x...",
"payload": {
"model": "claude-opus-4-6",
"messages": [
{ "role": "user", "content": "What's the weather?" }
],
"system": "You are a helpful assistant",
"maxTokens": 1000,
"temperature": 0.7
}
}Available models:
claude-opus-4-6(latest, most capable)claude-sonnet-4-5-20250929claude-haiku-4-5-20251001gpt-4ogpt-4o-minillama-3.1-70bllama-3.1-8bmixtral-8x7b
{
"wallet": "0x...",
"payload": {
"language": "python",
"code": "print('Hello World')",
"stdin": "",
"timeout": 30000,
"memoryMb": 256
}
}Supported languages: python, javascript, typescript, rust, go, bash
{
"wallet": "0x...",
"payload": {
"url": "https://example.com",
"method": "GET",
"headers": {},
"javascript": false,
"extract": {
"title": "title",
"heading": "h1"
}
}
}{
"wallet": "0x...",
"payload": {
"type": "price",
"query": {
"asset": "bitcoin"
}
}
}Data types: price, orderbook, candles, trades, markets, positions, balance, news, sentiment, percolator_state
{
"wallet": "0x...",
"payload": {
"platform": "polymarket",
"action": "buy",
"marketId": "0x...",
"size": 100,
"price": 0.55
}
}Supported platforms: polymarket, kalshi, hyperliquid, binance, bybit, mexc, jupiter, raydium, orca, percolator
Percolator-specific payload:
{
"wallet": "0x...",
"payload": {
"platform": "percolator",
"action": "long",
"size": 100,
"slabAddress": "A7wQtRT9DhFqYho8wTVqQCDc7kYPTUXGPATiyVbZKVFs"
}
}Scan code or addresses for security risks.
{
"wallet": "0x...",
"payload": {
"type": "code_scan",
"code": "const x = eval(input);"
}
}Security types: code_scan, address_check, token_audit, tx_validate
Token audit payload:
{
"wallet": "0x...",
"payload": {
"type": "token_audit",
"address": "0x...",
"chain": "ethereum"
}
}{
"wallet": "0x...",
"payload": {
"operation": "put",
"key": "my-file.txt",
"content": "Hello World",
"contentType": "text/plain",
"ttl": 3600
}
}Operations: put, get, delete, list
- Deposit USDC to the treasury wallet on Base network
- Include payment proof in your first request:
{ "paymentProof": { "txHash": "0x...", "network": "base", "amountUsd": 10.00, "token": "USDC", "timestamp": 1706500000000 } } - API verifies on-chain and credits your balance
- Subsequent requests just need your wallet address - balance is tracked server-side
{
"id": "req_123",
"jobId": "job_456",
"service": "llm",
"status": "failed",
"error": "Insufficient balance. Need $0.05, have $0.00",
"cost": 0,
"timestamp": 1706500000000
}If you provide a callbackUrl, the API will POST results when jobs complete:
{
"id": "req_123",
"jobId": "job_456",
"service": "llm",
"status": "completed",
"result": { ... },
"cost": 0.05,
"timestamp": 1706500000000
}The webhook includes an X-Clodds-Signature header (HMAC-SHA256) for verification.
Stream LLM responses via Server-Sent Events (SSE). This endpoint streams text chunks in real-time as the model generates them.
Request body:
{
"wallet": "0x...",
"payload": {
"model": "claude-opus-4-6",
"messages": [
{ "role": "user", "content": "Write a poem about coding" }
],
"system": "You are a creative writer",
"maxTokens": 1000,
"temperature": 0.7
}
}Response: Server-Sent Events stream
data: {"type": "start", "requestId": "req_123"}
data: {"type": "text", "text": "In "}
data: {"type": "text", "text": "the "}
data: {"type": "text", "text": "realm "}
data: {"type": "text", "text": "of "}
data: {"type": "text", "text": "code..."}
data: {"type": "usage", "usage": {"inputTokens": 25, "outputTokens": 150}}
data: {"type": "done", "response": {"content": "In the realm of code...", "model": "claude-opus-4-6", "usage": {"inputTokens": 25, "outputTokens": 150}, "stopReason": "end_turn"}}
Event types:
start: Stream initiated, includes requestIdtext: Text chunk from the modelusage: Token usage statisticserror: Error occurreddone: Stream complete, includes full response
JavaScript example:
const response = await fetch('https://api.cloddsbot.com/v1/stream/llm', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet: '0x...',
payload: {
model: 'claude-opus-4-6',
messages: [{ role: 'user', content: 'Hello' }]
}
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6));
if (data.type === 'text') {
process.stdout.write(data.text);
}
}
}
}Supported streaming models:
- All Claude models (via Anthropic streaming API)
- All GPT models (via OpenAI streaming API)
- All Together models (Llama, Mixtral)