Specula REST API

Programmatically control your Polymarket copy trading bot, manage wallets, read live portfolio data, and receive webhook events. Available exclusively on the Whale Protocol plan.

REST / JSON API Key Auth 500 req/day

Whale Protocol Required: API access is exclusive to Whale Protocol ($149/mo) subscribers. Shadow Trader and Alpha Hunter plans do not include API access. See pricing for plan details.

01

Overview

The Specula API is a RESTful interface that gives you full programmatic control over your Polymarket copy trading bot. Use it to build custom dashboards, trigger trades programmatically, integrate with your own trading infrastructure, or pipe data into analytics pipelines.

What You Can Do

  • Read your live portfolio balance, P&L, and position breakdown
  • List, add, and remove wallets from your tracked wallet set
  • Retrieve real-time trade signals from the copy engine
  • Pause, resume, and configure your bot remotely
  • Register webhook endpoints for push-based event delivery
  • Query the curated leaderboard and Ghost Wallet data

Data Format

All requests and responses use JSON. All monetary values are expressed in USDC with 6 decimal places (matching USDC's on-chain precision). Timestamps are Unix epoch integers (seconds). Wallet addresses are lowercased hex strings prefixed with 0x.

CORS & Usage

The API supports CORS for browser-based clients. For server-side usage (recommended for security), never expose your API key in client-side code. All requests must be made over HTTPS.

02

Authentication

Specula uses API key authentication. Your API key is tied to your wallet address and Whale Protocol subscription. All authenticated requests must include your key in the request header.

Generating Your API Key

Navigate to Dashboard → Settings → API Access and click Generate API Key. Your key is shown once — copy it immediately and store it securely. If lost, you can revoke the key and generate a new one at any time.

Request Header

X-PM-API-Key: pmk_whale_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API Key Format

API keys are prefixed with pmk_whale_ followed by a 32-character cryptographically random string. Keys are hashed before storage — Specula cannot retrieve your key after generation.

Key Revocation

Revoke your API key immediately if you believe it has been compromised. Active keys can be revoked from Dashboard → Settings → API Access → Revoke. Revocation takes effect within 30 seconds.

# Example authenticated request
curl -X GET https://api.specula.app/v1/portfolio \
-H "X-PM-API-Key: pmk_whale_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json"
03

Rate Limits

API requests are rate-limited per API key. Limits reset at midnight UTC each day.

Limit TypeValueNotes
Daily request limit500 requests/dayResets at 00:00 UTC
Per-minute burst30 requests/minuteRolling 60-second window
Webhook deliveriesUnlimitedPush events do not count against quota
Max response size10 MBPaginate large datasets

Rate Limit Headers

Every response includes rate limit headers:

X-RateLimit-Limit: 500
X-RateLimit-Remaining: 487
X-RateLimit-Reset: 1741305600 // UTC epoch of next reset

429 Handling

When you exceed the per-minute burst limit, you receive a 429 Too Many Requests response with a Retry-After header indicating seconds until your burst window resets. Implement exponential backoff in your client.

04

Base URL & Versioning

Base URL: https://api.specula.app/v1
Version: v1 (current stable)
Protocol: HTTPS only

The API is versioned via URL path prefix. The current stable version is v1. Breaking changes will be introduced in a new version (v2) with a minimum 90-day deprecation notice. Non-breaking additions (new fields, new endpoints) are added to the current version without notice.

Pagination

List endpoints support cursor-based pagination via cursor and limit query parameters. Responses include a next_cursor field; pass it as the cursor parameter in your next request. Maximum limit is 100. Default is 20.

GET /v1/positions?limit=50&cursor=pos_a7f3d9e2
05

Portfolio Endpoints

GET
/v1/portfolio
Returns your portfolio overview including USDC balance, total P&L, open position count, and 24h/7d performance metrics.
GET
/v1/portfolio/performance
Returns granular performance data. Supports period parameter: 24h, 7d, 30d, all.

GET /v1/portfolio — Response

{
"wallet": "0x1a2b3c4d5e6f...",
"plan": "whale_protocol",
"plan_expires_at": 1743897600,
"usdc_balance": "2480.500000",
"open_positions": 7,
"total_pnl": "+342.180000",
"pnl_24h": "+28.400000",
"pnl_7d": "+121.650000",
"win_rate": "0.68",
"bot_status": "active",
"updated_at": 1741305600
}
06

Position Endpoints

GET
/v1/positions
List all open positions. Filter with status=open|closed|all and category parameters.
GET
/v1/positions/{position_id}
Get details for a specific position including entry price, current price, P&L, and which tracked wallet triggered the entry.
DELETE
/v1/positions/{position_id}
Manually close a position. The bot will not re-enter this position until you clear the manual-close flag.

Position Object

{
"id": "pos_a7f3d9e2",
"market_id": "0x9a8b7c...",
"market_question": "Will BTC exceed $100k by end of Q2?",
"category": "crypto",
"side": "YES",
"size_usdc": "150.000000",
"entry_price": "0.62",
"current_price": "0.71",
"unrealized_pnl": "+21.780000",
"copied_from": "0xwhale1...",
"conviction_score": 74,
"status": "open",
"opened_at": 1741218000
}
07

Wallet Endpoints

GET
/v1/wallets
List all wallets currently in your tracking set, including curated and custom wallets.
POST
/v1/wallets
Add a custom wallet to your tracking set. Body: {"address": "0x..."}. Limited by your plan's custom wallet slot count.
PATCH
/v1/wallets/{address}
Update per-wallet settings: conviction threshold override, category filters, copy multiplier override, enabled/disabled state.
DELETE
/v1/wallets/{address}
Remove a custom wallet from your tracking set. Existing open positions from this wallet are not automatically closed.
GET
/v1/wallets/leaderboard
Returns the curated leaderboard. Parameters: sort=roi|winrate|volume, period=7d|30d, tier=top10|top50|top100.
GET
/v1/wallets/ghost
Returns Ghost Wallet Discovery™ results for your plan tier. Whale Protocol only returns the full unlimited pool.
08

Signal Endpoints

GET
/v1/signals
Returns the last 100 signals generated by the copy engine for your tracked wallets, including whether each was executed or filtered.
GET
/v1/signals/cascade
Returns Cascade Alert events for the past 7 days. Filter by status=fired|pending|expired.
GET
/v1/signals/arbitrage
Returns current live arbitrage gaps detected by the Probability Arbitrage Scanner™. Includes both platforms, probability values, and gap size.

Signal Object

{
"id": "sig_b9c1e3f5",
"type": "copy_entry", // copy_entry | copy_exit | cascade | arbitrage | contrarian
"source_wallet": "0xwhale1...",
"market_id": "0x9a8b7c...",
"side": "YES",
"conviction_score": 81,
"executed": true,
"execution_latency_ms": 147,
"filter_reason": null, // set if not executed (e.g. "below_conviction_threshold")
"detected_at": 1741305480
}
09

Bot Control Endpoints

GET
/v1/bot/status
Returns current bot status: active, paused, or stopped. Includes uptime since last activation and trade count for current session.
GET
/v1/bot/config
Returns full current bot configuration including all limits, filters, and feature flags.
PATCH
/v1/bot/config
Update bot configuration. Partial updates supported — send only the fields you want to change. Changes take effect on the next signal evaluation cycle.
POST
/v1/bot/pause
Pause the bot. Open positions are maintained; no new trades are executed. Monitoring continues.
POST
/v1/bot/resume
Resume the bot from paused state. The bot begins processing signals immediately.

PATCH /v1/bot/config — Request Body

{
"copy_multiplier": 1.5,
"max_trade_usdc": 200.0,
"daily_loss_limit_usdc": 500.0,
"min_conviction_score": 20,
"min_market_volume_usdc": 5000.0,
"max_open_positions": 15,
"exit_mirror_enabled": true,
"cascade_alert_enabled": true,
"cascade_min_wallets": 3,
"contrarian_mode_enabled": false,
"syndicate_mode_enabled": true,
"category_whitelist": ["elections", "crypto"]
}
10

Webhook Endpoints

Webhooks deliver real-time event payloads to your HTTPS endpoint as POST requests. Webhook delivery does not count against your API rate limit quota.

GET
/v1/webhooks
List all registered webhook endpoints and their event subscriptions.
POST
/v1/webhooks
Register a new webhook endpoint. Specify the URL and which event types to subscribe to.
DELETE
/v1/webhooks/{webhook_id}
Remove a webhook registration.

Event Types

  • trade.executed — Bot executed a copy trade (entry or exit)
  • trade.skipped — Signal detected but not executed (with reason)
  • cascade.fired — Cascade Alert triggered
  • arbitrage.detected — Arbitrage gap detected by scanner
  • bot.paused — Bot paused (manual or daily loss limit hit)
  • bot.resumed — Bot resumed
  • subscription.expiring — Subscription expires in 7/3/1 days
  • position.opened — New position opened
  • position.closed — Position closed (win or loss)

Webhook Payload

{
"event": "trade.executed",
"webhook_id": "wh_d4e5f6a7",
"timestamp": 1741305600,
"data": {
"signal_id": "sig_b9c1e3f5",
"position_id": "pos_a7f3d9e2",
"action": "entry",
"market_question": "Will BTC exceed $100k by end of Q2?",
"side": "YES",
"size_usdc": "150.000000",
"entry_price": "0.62",
"tx_hash": "0xabc123...",
"latency_ms": 147
}
}

Signature Verification

Each webhook request includes a X-PM-Signature header — an HMAC-SHA256 signature of the raw request body using your webhook secret. Always verify this signature before processing events.

# Node.js verification example
const crypto = require('crypto');
const sig = crypto
.createHmac('sha256', process.env.PM_WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
const valid = sig === req.headers['x-pm-signature'];
11

Error Reference

All errors return a JSON body with error code and human-readable message.

{
"error": "insufficient_plan",
"message": "This endpoint requires Whale Protocol plan.",
"status": 403
}
HTTP StatusError CodeDescription
400invalid_requestMalformed JSON, missing required field, or invalid parameter value
401unauthorizedMissing or invalid API key
403insufficient_planEndpoint requires a higher subscription tier
403subscription_expiredYour Whale Protocol subscription has expired
404not_foundResource ID does not exist or does not belong to your account
409wallet_already_trackedWallet address is already in your tracking set
409wallet_limit_reachedCustom wallet slot limit reached for your plan
422invalid_wallet_addressAddress is not a valid Ethereum wallet
429rate_limit_exceededDaily or per-minute request limit exceeded
500internal_errorServer-side error — check status.specula.app
503service_unavailableAPI temporarily offline for maintenance
12

Code Examples

Python — Get Portfolio & Pause Bot

import requests

API_KEY = "pmk_whale_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE = "https://api.specula.app/v1"
HEADERS = {"X-PM-API-Key": API_KEY}

# Get portfolio
portfolio = requests.get(f"{BASE}/portfolio", headers=HEADERS).json()
print(f"Balance: {portfolio['usdc_balance']} USDC")
print(f"P&L: {portfolio['total_pnl']} USDC")

# Pause bot if daily P&L drops below -$100
if float(portfolio['pnl_24h']) < -100:
requests.post(f"{BASE}/bot/pause", headers=HEADERS)
print("Bot paused — daily loss threshold hit")

JavaScript (Node.js) — List Signals & Send to Slack

const res = await fetch('https://api.specula.app/v1/signals', {
headers: { 'X-PM-API-Key': process.env.PM_API_KEY }
});
const { signals } = await res.json();

for (const sig of signals.filter(s => s.executed)) {
await fetch(process.env.SLACK_WEBHOOK, {
method: 'POST',
body: JSON.stringify({
text: `✅ Trade executed: ${sig.type} | Score: ${sig.conviction_score}`
})
});
}

cURL — Update Bot Config

curl -X PATCH https://api.specula.app/v1/bot/config \
-H "X-PM-API-Key: pmk_whale_xxxx..." \
-H "Content-Type: application/json" \
-d '{"copy_multiplier": 2.0, "min_conviction_score": 25}'

For full SDK support, community libraries, and more advanced examples, visit the GitHub repository. Report API bugs or request new endpoints via GitHub Issues.