Profitmaker API Reference
Profitmaker is an API-first, API-managed platform. All user state (dashboards, widgets, groups, exchange accounts, settings) is stored in PostgreSQL and managed through REST APIs. LLM agents, CLI tools, bots, and custom integrations can control the entire platform programmatically.
Server
- HTTP API:
http://localhost:3001(Bun + Elysia) - WebSocket:
http://localhost:3002(Socket.IO) - Database: PostgreSQL (via Drizzle ORM)
# Set up databaseexport DATABASE_URL="postgresql://user:password@localhost:5432/profitmaker"cd packages/server && bun db:push && cd ../..
# Start the serverbun server:dev
# Health checkcurl http://localhost:3001/healthEnvironment Variables
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | — | PostgreSQL connection string (required) |
PORT | 3001 | HTTP API port |
API_TOKEN | your-secret-token | Server-to-server auth token |
Authentication
Two auth methods are supported:
- Session token (for users) — obtained via
/api/auth/loginor/api/auth/register - API token (for server-to-server) — set via
API_TOKENenv var
# Register a new user (creates default dashboard with 6 widgets)curl -X POST http://localhost:3001/api/auth/register \ -H "Content-Type: application/json" \# Response: { "user": { "id": "uuid", "email": "...", "name": "..." }, "token": "session-uuid" }
# Logincurl -X POST http://localhost:3001/api/auth/login \ -H "Content-Type: application/json" \
# Use the token for all subsequent requestscurl http://localhost:3001/api/auth/me \ -H "Authorization: Bearer <token>"
# Logoutcurl -X POST http://localhost:3001/api/auth/logout \ -H "Authorization: Bearer <token>"All endpoints except /health and /api/auth/* require authentication.
User State API
Dashboards
# List all dashboardsGET /api/dashboards
# Get dashboard with all widgetsGET /api/dashboards/:id
# Create dashboardPOST /api/dashboardsBody: { "title": "My Dashboard", "description": "optional", "layout": {}, "isDefault": false }
# Update dashboardPUT /api/dashboards/:idBody: { "title": "New Title", "layout": { "gridSize": { "width": 1920, "height": 1080 } } }
# Delete dashboard (cascades to widgets)DELETE /api/dashboards/:idWidgets
# List widgets for a dashboardGET /api/widgets/dashboard/:dashboardId
# Create widgetPOST /api/widgetsBody: { "dashboardId": "uuid", "type": "chart", "defaultTitle": "BTC Chart", "position": { "x": 0, "y": 0, "width": 800, "height": 500, "zIndex": 1 }, "config": {}, "groupId": "optional-group-uuid"}
# Update widget (position, title, config, visibility)PUT /api/widgets/:idBody: { "position": { "x": 100, "y": 200, "width": 800, "height": 500, "zIndex": 1 } }
# Batch update positions (for drag-and-drop rearrangement)PUT /api/widgets/batchBody: { "widgets": [{ "id": "uuid1", "position": {...} }, { "id": "uuid2", "position": {...} }] }
# Delete widgetDELETE /api/widgets/:idWidget types: chart, orderbook, trades, orderForm, portfolio, userBalances, userTradingData, deals, transactionHistory, dataProviderSettings, dataProviderDebug, exchanges, markets, pairs.
Groups (Instrument Linking)
# List all groupsGET /api/groups
# Create groupPOST /api/groupsBody: { "name": "BTC Spot", "color": "#2196F3", "exchange": "binance", "market": "spot", "tradingPair": "BTC/USDT"}
# Update groupPUT /api/groups/:idBody: { "tradingPair": "ETH/USDT", "exchange": "bybit" }
# Delete groupDELETE /api/groups/:idColors: transparent, #00BCD4, #F44336, #9C27B0, #2196F3, #4CAF50, #FF9800, #E91E63.
Exchange Accounts
# List accounts (API keys are NOT returned)GET /api/accounts
# Add exchange accountPOST /api/accountsBody: { "exchange": "binance", "apiKey": "your-api-key", "secret": "your-secret", "password": "optional-passphrase", "label": "My Binance", "isEncrypted": true}
# Update accountPUT /api/accounts/:idBody: { "label": "Binance Main", "apiKey": "new-key" }
# Delete accountDELETE /api/accounts/:idUser Settings (Key-Value)
# Get all settingsGET /api/settings
# Get specific settingGET /api/settings/:key
# Set a setting (upsert)PUT /api/settings/:keyBody: { "value": "dark" }
# Bulk set settingsPUT /api/settingsBody: { "settings": { "theme": "dark", "activeDashboardId": "uuid", "selectedGroupId": "uuid" } }
# Delete a settingDELETE /api/settings/:keyCommon keys: activeDashboardId, selectedGroupId, activeProviderId, theme, dataFetchSettings.
Widget Settings (Per-Widget, Per-User)
# Get widget settingsGET /api/settings/widget/:widgetId
# Set widget settings (upsert)PUT /api/settings/widget/:widgetIdBody: { "settings": { "timeframe": "1h", "showVolume": true } }Data Providers
# List providersGET /api/providers
# Create providerPOST /api/providersBody: { "name": "My Server Provider", "type": "ccxt-server", "exchanges": ["binance", "bybit"], "priority": 50, "config": { "serverUrl": "http://localhost:3001", "token": "my-token" }}
# Update providerPUT /api/providers/:idBody: { "status": "disconnected", "priority": 100 }
# Delete providerDELETE /api/providers/:idProvider types: ccxt-browser, ccxt-server, marketmaker.cc, custom-server-with-adapter.
Market Data API
REST Endpoints
All require a config object specifying the exchange:
{ "exchangeId": "binance", "marketType": "spot", "ccxtType": "regular" }| Endpoint | Body | Description |
|---|---|---|
POST /api/exchange/instance | { config } | Create/get cached CCXT instance |
POST /api/exchange/fetchTicker | { config, symbol } | Fetch ticker |
POST /api/exchange/fetchOrderBook | { config, symbol, limit? } | Fetch order book |
POST /api/exchange/fetchTrades | { config, symbol, limit? } | Fetch trades |
POST /api/exchange/fetchOHLCV | { config, symbol, timeframe?, limit? } | Fetch candles |
POST /api/exchange/fetchBalance | { config } | Fetch balance (requires API keys) |
POST /api/exchange/capabilities | { config } | Get exchange features |
POST /api/exchange/watch* | { config, symbol } | CCXT Pro WebSocket (requires ccxtType: "pro") |
POST /api/proxy/request | { url, method?, headers?, body?, timeout? } | CORS proxy |
WebSocket (Socket.IO)
Connect to http://localhost:3002 for real-time streaming.
const socket = io('http://localhost:3002');socket.emit('authenticate', { token: 'your-token' });socket.on('authenticated', () => { socket.emit('subscribe', { exchangeId: 'binance', symbol: 'BTC/USDT', dataType: 'trades', // ticker | trades | orderbook | ohlcv | balance config: { exchangeId: 'binance', marketType: 'spot', ccxtType: 'pro' } });});socket.on('data', (msg) => console.log(msg.dataType, msg.data));socket.emit('unsubscribe', { subscriptionId: '...' });Database Schema
9 tables managed by Drizzle ORM:
| Table | Purpose |
|---|---|
users | User accounts (email, bcrypt password hash) |
sessions | Auth sessions (token, expiry, FK to user) |
dashboards | User dashboards (title, layout config) |
widgets | Widgets within dashboards (type, position, config) |
groups | Instrument linking groups (color, pair, exchange) |
exchange_accounts | Exchange API credentials (encrypted) |
data_providers | CCXT provider configurations |
user_settings | Key-value settings per user |
widget_settings | Per-widget per-user settings |
# Database management (run from packages/server/)bun db:push # Create/update tables from schemabun db:generate # Generate SQL migration filesbun db:migrate # Apply migrationsbun db:studio # Open Drizzle Studio GUIError Handling
{ "error": "Human-readable message", "details": "Technical details" }| Status | Meaning |
|---|---|
400 | Bad request (missing params, unsupported feature) |
401 | Missing or expired auth token |
403 | Invalid token / not your resource |
404 | Resource not found |
408 | Request timeout (proxy) |
409 | Conflict (e.g. email already registered) |
500 | Server error |
LLM Integration Guide
Complete workflow for an AI agent:
1. POST /api/auth/register -- create user account2. GET /health -- verify server running3. GET /api/dashboards -- list user's dashboards4. POST /api/widgets -- add a chart widget5. PUT /api/widgets/batch -- arrange widget positions6. POST /api/groups -- create instrument group (BTC/USDT on Binance)7. PUT /api/widgets/:id -- link widget to group8. POST /api/accounts -- add exchange API keys9. POST /api/exchange/capabilities -- discover exchange features10. POST /api/exchange/fetchTicker -- get current price11. Socket.IO subscribe to trades -- monitor real-time data