Predictu
API Reference

Admin (God Mode) API

Complete REST API reference for the Predictu internal administration dashboard - codename God Mode. These endpoints power the predictu-admin.vercel.app dashboard used by the Predictu ops team to onboard operators, monitor global risk, track revenue across every casino, and manage platform-wide settings.

Internal only. Every endpoint under /api/internal/* requires a valid Predictu admin session token passed via the Authorization: Bearer <token> header. Tokens are issued by the /api/auth/admin/login flow and carry the role: "predictu_admin" claim. Requests without a valid admin token receive a 401 Unauthorized response.

Authentication

All requests must include the admin JWT in the Authorization header. The token is validated against the Supabase admin_users table and must have the predictu_admin role. Tokens expire after 8 hours. A 403 Forbidden is returned if the token is valid but the user's admin role has been revoked.

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Standard Error Format

All error responses follow a consistent JSON envelope:

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Admin authentication required",
    "details": null
  }
}
HTTP StatusCodeMeaning
400BAD_REQUESTInvalid parameters or request body
401UNAUTHORIZEDMissing or expired admin token
403FORBIDDENValid token but insufficient permissions
404NOT_FOUNDResource does not exist
409CONFLICTDuplicate resource (e.g. operator slug)
422VALIDATION_ERRORSchema validation failed
429RATE_LIMITEDToo many requests (60 req/min per admin)
500INTERNAL_ERRORUnexpected server failure

Dashboard Overview

Returns the global platform summary displayed on the God Mode home screen. Aggregates data across all operators, including total revenue, active user counts, trade volume, exposure, and trend deltas compared to the previous period.

Get Dashboard

GET/api/internal/dashboard

Query Parameters

ParamTypeDefaultDescription
periodstring"7d"Time window for trend deltas. One of 1d, 7d, 30d, 90d, all.
operatorstringnullOptional operator slug to scope the dashboard to a single operator.

Response - 200 OK

{
  "data": {
    "operators": {
      "total": 12,
      "active": 9,
      "pending_onboarding": 2
    },
    "users": {
      "total": 48230,
      "active_24h": 3841,
      "active_7d": 12093,
      "new_7d": 1847,
      "delta_pct": 12.4
    },
    "trades": {
      "total": 892310,
      "volume_usd": 14832000.50,
      "count_24h": 18420,
      "volume_24h_usd": 312800.75,
      "delta_pct": 8.2
    },
    "revenue": {
      "total_usd": 743200.00,
      "period_usd": 48920.00,
      "delta_pct": 15.7,
      "breakdown": {
        "spread": 38200.00,
        "fees": 10720.00
      }
    },
    "exposure": {
      "current_usd": 284000.00,
      "max_usd": 500000.00,
      "utilization_pct": 56.8
    },
    "risk": {
      "circuit_breakers_active": 0,
      "high_exposure_markets": 3,
      "sharp_bettors_flagged": 14
    },
    "settlements": {
      "pending_count": 47,
      "pending_usd": 18400.00,
      "last_settled_at": "2026-03-19T08:12:00Z"
    },
    "chart_data": [
      { "date": "2026-03-12", "revenue_usd": 6800.00, "trades": 2400, "users": 1820 },
      { "date": "2026-03-13", "revenue_usd": 7120.00, "trades": 2580, "users": 1940 }
    ]
  }
}

Operators

Manage casino operators integrated with the Predictu platform. Each operator has a unique slug, branding configuration, S2S callback URL, embed origins, and associated users. Operators progress through onboarding stages: pendingconfiguringtestinglive.

List Operators

GET/api/internal/operators

Query Parameters

ParamTypeDefaultDescription
statusstringnullFilter by status: pending, configuring, testing, live, suspended.
searchstringnullFull-text search across operator name and slug.
sortstring"created_at"Sort field. One of created_at, name, revenue, users.
orderstring"desc"Sort order: asc or desc.

Response - 200 OK

{
  "data": [
    {
      "id": "op_abc123",
      "slug": "example-casino",
      "name": "Example Casino",
      "status": "live",
      "logo_url": "https://cdn.predictu.com/operators/example-casino/logo.png",
      "primary_color": "#00ff88",
      "s2s_enabled": true,
      "callback_url": "https://api.example-casino.com/predictu/callback",
      "embed_origins": ["https://example-casino.com", "https://www.example-casino.com"],
      "user_count": 8420,
      "trade_count": 214800,
      "revenue_total_usd": 128400.00,
      "revenue_30d_usd": 18200.00,
      "created_at": "2025-11-15T10:00:00Z",
      "onboarded_at": "2025-11-22T14:30:00Z"
    }
  ],
  "total": 12
}

Create Operator

POST/api/internal/operators

Registers a new casino operator on the platform. The operator starts in pending status and must complete the onboarding flow before going live. An API key pair is generated automatically and returned in the response.

Request Body

{
  "name": "Lucky Spins Casino",
  "slug": "lucky-spins",
  "contact_email": "integrations@luckyspins.com",
  "contact_name": "Alex Morgan",
  "website_url": "https://luckyspins.com",
  "callback_url": "https://api.luckyspins.com/predictu/callback",
  "s2s_enabled": true,
  "branding": {
    "primary_color": "#ff6b00",
    "secondary_color": "#1a1a2e",
    "logo_url": null,
    "favicon_url": null,
    "display_name": "Lucky Spins Predictions"
  },
  "embed_origins": ["https://luckyspins.com"],
  "config": {
    "max_bet_usd": 500,
    "min_bet_usd": 1,
    "default_currency": "USD",
    "allowed_categories": ["sports", "politics", "entertainment"],
    "risk_tier": "standard"
  }
}

Response - 201 Created

{
  "data": {
    "id": "op_xyz789",
    "slug": "lucky-spins",
    "name": "Lucky Spins Casino",
    "status": "pending",
    "api_key": "pk_live_abc123...",
    "api_secret": "sk_live_xyz789...",
    "created_at": "2026-03-19T12:00:00Z"
  }
}
Secret key shown once. The api_secret is only returned at creation time. Store it securely. If lost, a new key pair must be generated via the operator settings.

Get Operator Detail

GET/api/internal/operators/[slug]

Returns the full operator profile including branding, config, S2S status, and aggregated metrics.

Path Parameters

ParamTypeDescription
slugstringOperator's unique URL slug (e.g. example-casino).

Response - 200 OK

{
  "data": {
    "id": "op_abc123",
    "slug": "example-casino",
    "name": "Example Casino",
    "status": "live",
    "contact_email": "tech@example-casino.com",
    "contact_name": "Jordan Lee",
    "website_url": "https://example-casino.com",
    "callback_url": "https://api.example-casino.com/predictu/callback",
    "s2s_enabled": true,
    "s2s_healthy": true,
    "s2s_last_ping": "2026-03-19T11:58:00Z",
    "branding": {
      "primary_color": "#00ff88",
      "secondary_color": "#0a1a0a",
      "logo_url": "https://cdn.predictu.com/operators/example-casino/logo.png",
      "favicon_url": "https://cdn.predictu.com/operators/example-casino/favicon.png",
      "display_name": "Example Casino Predictions"
    },
    "embed_origins": ["https://example-casino.com", "https://www.example-casino.com"],
    "config": {
      "max_bet_usd": 1000,
      "min_bet_usd": 1,
      "default_currency": "USD",
      "allowed_categories": ["sports", "politics", "entertainment", "crypto"],
      "risk_tier": "premium",
      "spread_override": null,
      "custom_fees_bps": 150
    },
    "metrics": {
      "user_count": 8420,
      "active_users_24h": 642,
      "trade_count": 214800,
      "trade_volume_usd": 4280000.00,
      "revenue_total_usd": 128400.00,
      "revenue_30d_usd": 18200.00,
      "avg_trade_usd": 19.93,
      "exposure_usd": 42000.00
    },
    "onboarding": {
      "stage": "complete",
      "completed_steps": ["branding", "s2s_config", "embed_setup", "test_trades", "go_live"],
      "onboarded_at": "2025-11-22T14:30:00Z"
    },
    "created_at": "2025-11-15T10:00:00Z",
    "updated_at": "2026-03-18T09:00:00Z"
  }
}

Operator Revenue

GET/api/internal/operators/[slug]/revenue

Returns time-series revenue data for a specific operator, broken down by source (spread, fees, settlements).

Query Parameters

ParamTypeDefaultDescription
fromstring30 days agoISO 8601 start date.
tostringnowISO 8601 end date.
granularitystring"day"One of hour, day, week, month.

Response - 200 OK

{
  "data": {
    "operator_slug": "example-casino",
    "period": { "from": "2026-02-17T00:00:00Z", "to": "2026-03-19T23:59:59Z" },
    "totals": {
      "revenue_usd": 18200.00,
      "spread_revenue_usd": 14200.00,
      "fee_revenue_usd": 4000.00,
      "predictu_share_usd": 5460.00,
      "operator_share_usd": 12740.00
    },
    "series": [
      {
        "date": "2026-03-18",
        "revenue_usd": 620.00,
        "spread_usd": 480.00,
        "fees_usd": 140.00,
        "trade_count": 890,
        "volume_usd": 17800.00
      }
    ]
  }
}

Operator Trades

GET/api/internal/operators/[slug]/trades

Returns paginated trade history for an operator. Supports filtering by market, user, side, and date range.

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number (1-indexed).
limitnumber50Results per page. Max 200.
user_idstringnullFilter by user ID.
market_idstringnullFilter by market ID.
sidestringnullFilter by side: buy or sell.
outcomestringnullFilter by outcome: yes or no.
fromstringnullISO 8601 start date.
tostringnullISO 8601 end date.
sortstring"created_at"Sort field: created_at, amount, price.
orderstring"desc"Sort order: asc or desc.

Response - 200 OK

{
  "data": [
    {
      "id": "trd_abc123",
      "user_id": "usr_xyz",
      "user_name": "player_42",
      "operator_slug": "example-casino",
      "market_id": "mkt_001",
      "market_title": "Will BTC exceed $150k by April 2026?",
      "outcome": "yes",
      "side": "buy",
      "price": 0.62,
      "quantity": 50.00,
      "cost_usd": 31.00,
      "fee_usd": 0.47,
      "spread_usd": 0.93,
      "pnl_usd": null,
      "status": "open",
      "created_at": "2026-03-19T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 214800,
    "total_pages": 4296
  }
}

Operator Users

GET/api/internal/operators/[slug]/users

Returns paginated list of users registered under a specific operator, with account metrics.

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page. Max 200.
searchstringnullSearch by username, email, or external ID.
tierstringnullFilter by risk tier: normal, sharp, restricted, banned.
statusstringnullFilter by status: active, inactive, suspended.
sortstring"created_at"Sort: created_at, last_active, trade_count, balance, pnl.
orderstring"desc"Sort order.

Response - 200 OK

{
  "data": [
    {
      "id": "usr_xyz",
      "external_id": "gbn_player_42",
      "username": "player_42",
      "email": "player42@email.com",
      "operator_slug": "example-casino",
      "tier": "normal",
      "status": "active",
      "balance_usd": 142.50,
      "trade_count": 84,
      "volume_usd": 2480.00,
      "pnl_usd": 38.20,
      "win_rate": 0.54,
      "score": 42,
      "last_active_at": "2026-03-19T10:15:00Z",
      "created_at": "2026-01-08T18:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 8420,
    "total_pages": 169
  }
}

Operator Exposure

GET/api/internal/operators/[slug]/exposure

Returns the current risk exposure for a specific operator, broken down by market and category. Exposure represents the maximum potential payout if all open positions resolve in the worst-case direction.

Response - 200 OK

{
  "data": {
    "operator_slug": "example-casino",
    "total_exposure_usd": 42000.00,
    "exposure_limit_usd": 100000.00,
    "utilization_pct": 42.0,
    "by_category": [
      { "category": "sports", "exposure_usd": 22000.00, "limit_usd": 50000.00, "utilization_pct": 44.0 },
      { "category": "politics", "exposure_usd": 12000.00, "limit_usd": 30000.00, "utilization_pct": 40.0 },
      { "category": "crypto", "exposure_usd": 8000.00, "limit_usd": 20000.00, "utilization_pct": 40.0 }
    ],
    "by_market": [
      {
        "market_id": "mkt_001",
        "title": "Will BTC exceed $150k by April 2026?",
        "exposure_usd": 8400.00,
        "yes_exposure_usd": 5200.00,
        "no_exposure_usd": 3200.00,
        "position_count": 142,
        "volume_usd": 28400.00
      }
    ],
    "top_users": [
      { "user_id": "usr_abc", "username": "highroller_99", "exposure_usd": 4800.00, "tier": "sharp" }
    ]
  }
}

Operator Invoices

GET/api/internal/operators/[slug]/invoices

Returns the billing history for an operator. Invoices are generated monthly and represent Predictu's revenue share from the operator's net player losses.

Query Parameters

ParamTypeDefaultDescription
statusstringnullFilter: draft, sent, paid, overdue.
fromstringnullISO 8601 start date.
tostringnullISO 8601 end date.

Response - 200 OK

{
  "data": [
    {
      "id": "inv_001",
      "operator_slug": "example-casino",
      "period": { "from": "2026-02-01", "to": "2026-02-28" },
      "status": "paid",
      "amount_usd": 5460.00,
      "trade_volume_usd": 182000.00,
      "trade_count": 8420,
      "spread_revenue_usd": 4200.00,
      "fee_revenue_usd": 1260.00,
      "revenue_share_pct": 30,
      "issued_at": "2026-03-01T00:00:00Z",
      "paid_at": "2026-03-05T14:20:00Z",
      "pdf_url": "/api/internal/invoices/inv_001/pdf"
    }
  ],
  "total": 4
}

Users

Global user management across all operators. Supports full-text search, risk tier filtering, operator filtering, and detailed user drill-down with ledger history, positions, trades, and scoring data.

List Users

GET/api/internal/users

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number (1-indexed).
limitnumber50Results per page. Max 200.
searchstringnullSearch by username, email, external ID, or user ID.
operatorstringnullFilter by operator slug.
tierstringnullFilter by risk tier: normal, sharp, restricted, banned.
statusstringnullFilter by account status: active, inactive, suspended.
min_balancenumbernullMinimum balance in USD.
max_balancenumbernullMaximum balance in USD.
sortstring"created_at"Sort: created_at, last_active, balance, trade_count, pnl, score.
orderstring"desc"Sort order.

Response - 200 OK

{
  "data": [
    {
      "id": "usr_xyz",
      "external_id": "gbn_player_42",
      "username": "player_42",
      "email": "player42@email.com",
      "operator_slug": "example-casino",
      "operator_name": "Example Casino",
      "tier": "normal",
      "status": "active",
      "balance_usd": 142.50,
      "trade_count": 84,
      "volume_usd": 2480.00,
      "pnl_usd": 38.20,
      "win_rate": 0.54,
      "score": 42,
      "open_positions": 5,
      "last_active_at": "2026-03-19T10:15:00Z",
      "created_at": "2026-01-08T18:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 48230,
    "total_pages": 965
  }
}

Get User Detail

GET/api/internal/users/[id]

Returns the full user profile with account metrics, scoring breakdown, and risk tier assessment.

Path Parameters

ParamTypeDescription
idstringUser ID (e.g. usr_xyz).

Response - 200 OK

{
  "data": {
    "id": "usr_xyz",
    "external_id": "gbn_player_42",
    "username": "player_42",
    "email": "player42@email.com",
    "operator_slug": "example-casino",
    "operator_name": "Example Casino",
    "tier": "normal",
    "status": "active",
    "balance_usd": 142.50,
    "metrics": {
      "trade_count": 84,
      "volume_usd": 2480.00,
      "pnl_usd": 38.20,
      "win_rate": 0.54,
      "avg_trade_usd": 29.52,
      "largest_trade_usd": 200.00,
      "open_positions": 5,
      "total_deposited_usd": 500.00,
      "total_withdrawn_usd": 300.00,
      "exposure_usd": 280.00
    },
    "scoring": {
      "score": 42,
      "tier": "normal",
      "components": {
        "win_rate_score": 12,
        "edge_detection_score": 8,
        "timing_score": 6,
        "volume_pattern_score": 10,
        "correlation_score": 6
      },
      "flags": [],
      "last_evaluated_at": "2026-03-19T08:00:00Z"
    },
    "restrictions": {
      "max_bet_usd": 1000,
      "allowed_categories": null,
      "blocked_markets": [],
      "cooldown_until": null
    },
    "last_active_at": "2026-03-19T10:15:00Z",
    "created_at": "2026-01-08T18:30:00Z",
    "updated_at": "2026-03-19T10:15:00Z"
  }
}

User Ledger

GET/api/internal/users/[id]/ledger

Returns the immutable financial ledger for a user. Every balance-affecting action is recorded here: deposits, withdrawals, trade debits, trade credits, settlement payouts, fee deductions, and admin adjustments. This is the audit trail for any balance dispute.

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page. Max 200.
typestringnullFilter: deposit, withdraw, trade_debit, trade_credit, settlement, fee, adjustment.
fromstringnullISO 8601 start date.
tostringnullISO 8601 end date.

Response - 200 OK

{
  "data": [
    {
      "id": "ldg_001",
      "user_id": "usr_xyz",
      "type": "trade_debit",
      "amount_usd": -31.00,
      "balance_before_usd": 173.50,
      "balance_after_usd": 142.50,
      "reference_type": "trade",
      "reference_id": "trd_abc123",
      "description": "Buy 50 YES @ $0.62 - Will BTC exceed $150k by April 2026?",
      "metadata": {
        "market_id": "mkt_001",
        "outcome": "yes",
        "side": "buy",
        "price": 0.62,
        "quantity": 50.00
      },
      "idempotency_key": "idk_trd_abc123",
      "created_at": "2026-03-19T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 412,
    "total_pages": 9
  }
}

User Positions

GET/api/internal/users/[id]/positions

Returns all positions (open and closed) for a user across all markets.

Query Parameters

ParamTypeDefaultDescription
statusstringnullFilter: open, closed, settled.
pagenumber1Page number.
limitnumber50Results per page.

Response - 200 OK

{
  "data": [
    {
      "id": "pos_001",
      "user_id": "usr_xyz",
      "market_id": "mkt_001",
      "market_title": "Will BTC exceed $150k by April 2026?",
      "outcome": "yes",
      "quantity": 50.00,
      "avg_price": 0.62,
      "cost_basis_usd": 31.00,
      "current_price": 0.68,
      "market_value_usd": 34.00,
      "unrealized_pnl_usd": 3.00,
      "realized_pnl_usd": 0.00,
      "status": "open",
      "opened_at": "2026-03-19T10:30:00Z",
      "closed_at": null,
      "settled_at": null
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 5,
    "total_pages": 1
  }
}

User Trades

GET/api/internal/users/[id]/trades

Returns all trades executed by a specific user. Same schema as the global trades endpoint, scoped to one user.

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page.
market_idstringnullFilter by market.
sidestringnullFilter: buy or sell.
fromstringnullISO 8601 start date.
tostringnullISO 8601 end date.

Response - 200 OK

{
  "data": [
    {
      "id": "trd_abc123",
      "user_id": "usr_xyz",
      "market_id": "mkt_001",
      "market_title": "Will BTC exceed $150k by April 2026?",
      "outcome": "yes",
      "side": "buy",
      "price": 0.62,
      "quantity": 50.00,
      "cost_usd": 31.00,
      "fee_usd": 0.47,
      "spread_usd": 0.93,
      "status": "filled",
      "created_at": "2026-03-19T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 84,
    "total_pages": 2
  }
}

User Score

GET/api/internal/users/[id]/score

Returns the detailed scoring breakdown for a user. The scoring system detects sharp bettors using five components: win rate analysis, edge detection (beating closing line), timing patterns, volume patterns, and cross-market correlation. Scores range from 0 (recreational) to 100 (sharp).

Response - 200 OK

{
  "data": {
    "user_id": "usr_xyz",
    "score": 42,
    "tier": "normal",
    "tier_thresholds": {
      "normal": { "min": 0, "max": 59 },
      "sharp": { "min": 60, "max": 79 },
      "restricted": { "min": 80, "max": 100 }
    },
    "components": {
      "win_rate": {
        "score": 12,
        "max": 25,
        "value": 0.54,
        "detail": "Win rate 54% - slightly above baseline (50%)"
      },
      "edge_detection": {
        "score": 8,
        "max": 25,
        "value": 0.02,
        "detail": "Avg CLV edge +2% - minimal"
      },
      "timing": {
        "score": 6,
        "max": 20,
        "value": 0.15,
        "detail": "15% of bets placed within 5min of line movement"
      },
      "volume_pattern": {
        "score": 10,
        "max": 15,
        "value": 0.8,
        "detail": "Consistent sizing, no spike patterns"
      },
      "correlation": {
        "score": 6,
        "max": 15,
        "value": 0.12,
        "detail": "Low cross-market correlation (0.12)"
      }
    },
    "history": [
      { "date": "2026-03-12", "score": 40 },
      { "date": "2026-03-05", "score": 38 },
      { "date": "2026-02-26", "score": 35 }
    ],
    "flags": [],
    "recommendations": [],
    "last_evaluated_at": "2026-03-19T08:00:00Z"
  }
}

Trades

Global trade management across all operators. Each trade record represents an atomic execution: a buy or sell of an outcome share at a specific price. Trades are immutable once created.

List Trades

GET/api/internal/trades

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page. Max 200.
operatorstringnullFilter by operator slug.
user_idstringnullFilter by user ID.
market_idstringnullFilter by market ID.
sidestringnullFilter: buy or sell.
outcomestringnullFilter: yes or no.
statusstringnullFilter: filled, settled, cancelled.
min_amountnumbernullMinimum trade amount in USD.
max_amountnumbernullMaximum trade amount in USD.
fromstringnullISO 8601 start date.
tostringnullISO 8601 end date.
sortstring"created_at"Sort: created_at, amount, price.
orderstring"desc"Sort order.

Response - 200 OK

{
  "data": [
    {
      "id": "trd_abc123",
      "user_id": "usr_xyz",
      "user_name": "player_42",
      "operator_slug": "example-casino",
      "operator_name": "Example Casino",
      "market_id": "mkt_001",
      "market_title": "Will BTC exceed $150k by April 2026?",
      "category": "crypto",
      "outcome": "yes",
      "side": "buy",
      "price": 0.62,
      "quantity": 50.00,
      "cost_usd": 31.00,
      "fee_usd": 0.47,
      "spread_usd": 0.93,
      "pnl_usd": null,
      "status": "filled",
      "s2s_transaction_id": "txn_gbn_abc123",
      "idempotency_key": "idk_trd_abc123",
      "created_at": "2026-03-19T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 892310,
    "total_pages": 17847
  }
}

Markets

Browse and inspect all prediction markets on the platform. Markets are sourced from Polymarket and mapped through the Predictu tradeability filter. Includes pricing data, volume, and resolution status.

List Markets

GET/api/internal/markets

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page. Max 200.
searchstringnullFull-text search on market title and description.
categorystringnullFilter: sports, politics, entertainment, crypto, science, business.
statusstringnullFilter: active, paused, resolved, cancelled.
tradeablebooleannullFilter by tradeability flag (passed Predictu selection criteria).
sortstring"volume"Sort: volume, created_at, end_date, exposure, trade_count.
orderstring"desc"Sort order.

Response - 200 OK

{
  "data": [
    {
      "id": "mkt_001",
      "polymarket_id": "pm_condition_abc",
      "title": "Will BTC exceed $150k by April 2026?",
      "description": "Resolves YES if Bitcoin trades above $150,000...",
      "category": "crypto",
      "status": "active",
      "tradeable": true,
      "image_url": "https://cdn.predictu.com/markets/mkt_001.png",
      "yes_price": 0.62,
      "no_price": 0.38,
      "spread": 0.04,
      "volume_usd": 482000.00,
      "trade_count": 12400,
      "position_count": 3200,
      "exposure_usd": 28400.00,
      "liquidity_score": 0.89,
      "end_date": "2026-04-30T23:59:59Z",
      "resolution": null,
      "resolved_at": null,
      "created_at": "2026-01-15T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 842,
    "total_pages": 17
  }
}

Get Market Detail

GET/api/internal/markets/[id]

Returns full market detail including pricing history, operator-level breakdown, and risk metrics.

Response - 200 OK

{
  "data": {
    "id": "mkt_001",
    "polymarket_id": "pm_condition_abc",
    "title": "Will BTC exceed $150k by April 2026?",
    "description": "Resolves YES if Bitcoin price exceeds $150,000 USD on any major exchange before April 30, 2026 23:59 UTC.",
    "category": "crypto",
    "tags": ["bitcoin", "price", "crypto"],
    "status": "active",
    "tradeable": true,
    "image_url": "https://cdn.predictu.com/markets/mkt_001.png",
    "pricing": {
      "yes_price": 0.62,
      "no_price": 0.38,
      "spread": 0.04,
      "base_spread": 0.02,
      "risk_adjusted_spread": 0.04,
      "last_updated": "2026-03-19T11:58:00Z"
    },
    "volume": {
      "total_usd": 482000.00,
      "24h_usd": 12400.00,
      "7d_usd": 68000.00,
      "trade_count": 12400,
      "unique_traders": 2840
    },
    "exposure": {
      "total_usd": 28400.00,
      "yes_usd": 18200.00,
      "no_usd": 10200.00,
      "imbalance_ratio": 1.78,
      "position_count": 3200
    },
    "by_operator": [
      {
        "operator_slug": "example-casino",
        "volume_usd": 148000.00,
        "trade_count": 3800,
        "exposure_usd": 8400.00,
        "user_count": 920
      }
    ],
    "price_history": [
      { "timestamp": "2026-03-19T11:00:00Z", "yes_price": 0.61, "volume_usd": 480.00 },
      { "timestamp": "2026-03-19T12:00:00Z", "yes_price": 0.62, "volume_usd": 520.00 }
    ],
    "resolution": null,
    "resolution_source": null,
    "resolved_at": null,
    "end_date": "2026-04-30T23:59:59Z",
    "created_at": "2026-01-15T00:00:00Z",
    "updated_at": "2026-03-19T11:58:00Z"
  }
}

Global Exposure

Real-time view of platform-wide risk exposure. Exposure is the maximum potential payout if all open positions resolve in the worst-case direction. The 5-wall risk system enforces limits at per-trade, per-market, per-category, per-operator, and global levels.

Get Global Exposure

GET/api/internal/exposure

Response - 200 OK

{
  "data": {
    "total_exposure_usd": 284000.00,
    "global_limit_usd": 500000.00,
    "utilization_pct": 56.8,
    "by_operator": [
      {
        "operator_slug": "example-casino",
        "exposure_usd": 42000.00,
        "limit_usd": 100000.00,
        "utilization_pct": 42.0
      }
    ],
    "by_category": [
      { "category": "sports", "exposure_usd": 120000.00, "limit_usd": 200000.00, "utilization_pct": 60.0 },
      { "category": "crypto", "exposure_usd": 84000.00, "limit_usd": 150000.00, "utilization_pct": 56.0 },
      { "category": "politics", "exposure_usd": 52000.00, "limit_usd": 100000.00, "utilization_pct": 52.0 },
      { "category": "entertainment", "exposure_usd": 28000.00, "limit_usd": 50000.00, "utilization_pct": 56.0 }
    ],
    "top_markets": [
      {
        "market_id": "mkt_001",
        "title": "Will BTC exceed $150k by April 2026?",
        "exposure_usd": 28400.00,
        "limit_usd": 50000.00,
        "position_count": 3200
      }
    ],
    "top_users": [
      {
        "user_id": "usr_high1",
        "username": "whale_trader",
        "operator_slug": "example-casino",
        "exposure_usd": 12000.00,
        "tier": "sharp"
      }
    ],
    "alerts": [
      {
        "level": "warning",
        "message": "Category 'sports' approaching 60% utilization",
        "category": "sports",
        "created_at": "2026-03-19T11:00:00Z"
      }
    ],
    "snapshot_at": "2026-03-19T12:00:00Z"
  }
}

Risk Management

The risk engine provides real-time monitoring, circuit breaker management, risk event logging, and sharp bettor tracking. Circuit breakers can automatically halt trading on specific markets or globally when risk thresholds are exceeded.

Get Risk Overview

GET/api/internal/risk

Response - 200 OK

{
  "data": {
    "status": "healthy",
    "circuit_breakers": {
      "global_active": false,
      "market_breakers": 0,
      "category_breakers": 0,
      "operator_breakers": 0
    },
    "exposure_summary": {
      "total_usd": 284000.00,
      "limit_usd": 500000.00,
      "utilization_pct": 56.8
    },
    "sharp_bettors": {
      "flagged_count": 14,
      "restricted_count": 3,
      "banned_count": 1
    },
    "recent_events_count": 42,
    "risk_score": 38,
    "risk_level": "moderate",
    "walls": {
      "wall_1_per_trade": { "status": "green", "violations_24h": 12 },
      "wall_2_per_market": { "status": "green", "violations_24h": 3 },
      "wall_3_per_category": { "status": "yellow", "violations_24h": 1 },
      "wall_4_per_operator": { "status": "green", "violations_24h": 0 },
      "wall_5_global": { "status": "green", "violations_24h": 0 }
    }
  }
}

Circuit Breakers

GET/api/internal/risk/circuit-breakers

Returns all configured circuit breakers with their current state. Circuit breakers can be scoped to a specific market, category, operator, or applied globally. When tripped, all new trades in the affected scope are rejected until the breaker is manually reset or the cooldown expires.

Response - 200 OK

{
  "data": [
    {
      "id": "cb_001",
      "scope": "market",
      "scope_id": "mkt_001",
      "scope_label": "Will BTC exceed $150k by April 2026?",
      "trigger_type": "exposure_pct",
      "trigger_threshold": 90,
      "current_value": 56.8,
      "status": "armed",
      "cooldown_minutes": 60,
      "auto_reset": true,
      "tripped_at": null,
      "reset_at": null,
      "created_by": "admin_001",
      "created_at": "2026-02-01T10:00:00Z"
    },
    {
      "id": "cb_002",
      "scope": "global",
      "scope_id": null,
      "scope_label": "Global",
      "trigger_type": "exposure_pct",
      "trigger_threshold": 95,
      "current_value": 56.8,
      "status": "armed",
      "cooldown_minutes": 120,
      "auto_reset": false,
      "tripped_at": null,
      "reset_at": null,
      "created_by": "admin_001",
      "created_at": "2026-01-15T10:00:00Z"
    }
  ],
  "total": 8
}

Risk Events

GET/api/internal/risk/events

Returns a paginated log of risk events. Risk events are generated when wall limits are approached or breached, when circuit breakers trip, when sharp bettor thresholds change, and when unusual trading patterns are detected.

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page.
severitystringnullFilter: info, warning, critical.
typestringnullFilter: wall_violation, circuit_breaker, sharp_detection, anomaly.
fromstringnullISO 8601 start date.
tostringnullISO 8601 end date.

Response - 200 OK

{
  "data": [
    {
      "id": "evt_001",
      "type": "wall_violation",
      "severity": "warning",
      "wall": 3,
      "wall_name": "per_category",
      "message": "Category 'sports' exposure hit 60% utilization (120k/200k USD)",
      "scope": { "category": "sports" },
      "value": 120000.00,
      "threshold": 200000.00,
      "utilization_pct": 60.0,
      "operator_slug": null,
      "user_id": null,
      "market_id": null,
      "auto_resolved": false,
      "resolved_at": null,
      "created_at": "2026-03-19T11:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 42,
    "total_pages": 1
  }
}

Sharp Bettors

GET/api/internal/risk/sharps

Returns all users whose scoring tier is sharp or above, with detailed scoring breakdown and betting patterns. Used for manual review and tier override decisions.

Query Parameters

ParamTypeDefaultDescription
tierstringnullFilter: sharp, restricted, banned.
operatorstringnullFilter by operator slug.
sortstring"score"Sort: score, pnl, volume, win_rate.
orderstring"desc"Sort order.

Response - 200 OK

{
  "data": [
    {
      "user_id": "usr_sharp1",
      "username": "edge_hunter",
      "operator_slug": "example-casino",
      "tier": "sharp",
      "score": 72,
      "win_rate": 0.64,
      "pnl_usd": 4820.00,
      "volume_usd": 38400.00,
      "trade_count": 420,
      "clv_edge": 0.08,
      "timing_score": 16,
      "restrictions": {
        "max_bet_usd": 100,
        "blocked_categories": ["sports"],
        "cooldown_until": null
      },
      "last_evaluated_at": "2026-03-19T08:00:00Z"
    }
  ],
  "total": 14
}

Settlements

When a market resolves, positions are settled: winning positions receive payouts, losing positions are closed at zero. The settlement engine processes all positions atomically per market and generates ledger entries and S2S callbacks for each affected user.

List Settlements

GET/api/internal/settlements

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page.
statusstringnullFilter: pending, processing, completed, failed.
market_idstringnullFilter by market.
operatorstringnullFilter by operator slug.

Response - 200 OK

{
  "data": [
    {
      "id": "stl_001",
      "market_id": "mkt_042",
      "market_title": "Will the Fed cut rates in March 2026?",
      "resolution": "yes",
      "status": "completed",
      "positions_settled": 840,
      "winners": 520,
      "losers": 320,
      "total_payout_usd": 14200.00,
      "total_loss_usd": 9800.00,
      "net_pnl_usd": -4400.00,
      "s2s_callbacks_sent": 840,
      "s2s_callbacks_confirmed": 838,
      "s2s_callbacks_failed": 2,
      "processing_time_ms": 3420,
      "resolved_at": "2026-03-18T20:00:00Z",
      "settled_at": "2026-03-18T20:00:03Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 284,
    "total_pages": 6
  }
}

Pending Settlements

GET/api/internal/settlements/pending

Returns markets that have resolved but whose positions have not yet been fully settled. This includes markets in processing state and those with failed S2S callbacks awaiting retry.

Response - 200 OK

{
  "data": [
    {
      "market_id": "mkt_099",
      "market_title": "Will ETH flip BTC in market cap by Q2 2026?",
      "resolution": "no",
      "resolved_at": "2026-03-19T08:00:00Z",
      "status": "processing",
      "positions_total": 420,
      "positions_settled": 380,
      "positions_remaining": 40,
      "failed_callbacks": [
        {
          "user_id": "usr_fail1",
          "operator_slug": "lucky-spins",
          "error": "S2S callback timeout after 3 retries",
          "last_attempt_at": "2026-03-19T08:05:00Z",
          "retry_count": 3
        }
      ]
    }
  ],
  "total": 2
}

Invoices

Monthly billing invoices for operator revenue sharing. Invoices are auto-generated on the 1st of each month for the prior period. Each invoice itemizes player losses by source (spread, fees) and the Predictu revenue share percentage (% of player losses).

List Invoices

GET/api/internal/invoices

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number.
limitnumber50Results per page.
operatorstringnullFilter by operator slug.
statusstringnullFilter: draft, sent, paid, overdue.

Response - 200 OK

{
  "data": [
    {
      "id": "inv_001",
      "operator_slug": "example-casino",
      "operator_name": "Example Casino",
      "period": { "from": "2026-02-01", "to": "2026-02-28" },
      "status": "paid",
      "amount_usd": 5460.00,
      "line_items": [
        { "description": "Predictu share of spread player losses (30%)", "amount_usd": 4260.00 },
        { "description": "Predictu share of fee player losses (30%)", "amount_usd": 1200.00 }
      ],
      "trade_volume_usd": 182000.00,
      "trade_count": 8420,
      "revenue_share_pct": 30,
      "issued_at": "2026-03-01T00:00:00Z",
      "due_at": "2026-03-15T00:00:00Z",
      "paid_at": "2026-03-05T14:20:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 36,
    "total_pages": 1
  }
}

Get Invoice Detail

GET/api/internal/invoices/[id]

Returns full invoice detail with line items and payment history.

Response - 200 OK

{
  "data": {
    "id": "inv_001",
    "operator_slug": "example-casino",
    "operator_name": "Example Casino",
    "operator_contact_email": "billing@example-casino.com",
    "period": { "from": "2026-02-01", "to": "2026-02-28" },
    "status": "paid",
    "amount_usd": 5460.00,
    "line_items": [
      { "description": "Player losses from spread - 8,420 trades", "gross_usd": 14200.00, "share_pct": 30, "amount_usd": 4260.00 },
      { "description": "Player losses from fees - 8,420 trades", "gross_usd": 4000.00, "share_pct": 30, "amount_usd": 1200.00 }
    ],
    "summary": {
      "trade_volume_usd": 182000.00,
      "trade_count": 8420,
      "unique_traders": 2100,
      "gross_revenue_usd": 18200.00,
      "predictu_share_usd": 5460.00,
      "operator_share_usd": 12740.00,
      "revenue_share_pct": 30
    },
    "payment": {
      "method": "wire",
      "reference": "WIR-2026-0305-001",
      "paid_at": "2026-03-05T14:20:00Z"
    },
    "issued_at": "2026-03-01T00:00:00Z",
    "due_at": "2026-03-15T00:00:00Z",
    "created_at": "2026-03-01T00:00:00Z"
  }
}

Download Invoice PDF

GET/api/internal/invoices/[id]/pdf

Returns the invoice as a PDF binary download. The response has Content-Type: application/pdf andContent-Disposition: attachment; filename="invoice-inv_001.pdf".

Response - 200 OK

Binary PDF file stream. No JSON body.

Revenue

Platform-wide revenue analytics. Revenue represents net player losses, which come from two sources: the spread (difference between displayed price and Polymarket mid-price) and explicit trading fees. Predictu takes an agreed percentage of player losses from each operator per their revenue_share_pct.

Get Revenue

GET/api/internal/revenue

Query Parameters

ParamTypeDefaultDescription
fromstring30 days agoISO 8601 start date.
tostringnowISO 8601 end date.
granularitystring"day"Aggregation: hour, day, week, month.
operatorstringnullFilter by operator slug.

Response - 200 OK

{
  "data": {
    "period": { "from": "2026-02-17T00:00:00Z", "to": "2026-03-19T23:59:59Z" },
    "totals": {
      "gross_revenue_usd": 148200.00,
      "spread_revenue_usd": 112000.00,
      "fee_revenue_usd": 36200.00,
      "predictu_share_usd": 44460.00,
      "operator_share_usd": 103740.00,
      "trade_volume_usd": 4940000.00,
      "trade_count": 98420,
      "unique_traders": 12400,
      "revenue_per_trade_usd": 1.51
    },
    "by_operator": [
      {
        "operator_slug": "example-casino",
        "gross_usd": 48200.00,
        "predictu_share_usd": 14460.00,
        "trade_count": 32000
      }
    ],
    "series": [
      {
        "date": "2026-03-18",
        "gross_usd": 4800.00,
        "spread_usd": 3600.00,
        "fees_usd": 1200.00,
        "predictu_usd": 1440.00,
        "trades": 3200,
        "volume_usd": 160000.00
      }
    ]
  }
}

Revenue Forecast

GET/api/internal/revenue/forecast

Returns projected revenue for the next 30/60/90 days based on historical trends, operator growth rates, and seasonal patterns. Used for financial planning and capacity forecasting.

Query Parameters

ParamTypeDefaultDescription
horizonstring"30d"Forecast horizon: 30d, 60d, 90d.

Response - 200 OK

{
  "data": {
    "horizon": "30d",
    "projected_revenue_usd": 162000.00,
    "confidence_interval": {
      "low_usd": 142000.00,
      "high_usd": 184000.00,
      "confidence_pct": 80
    },
    "growth_rate_pct": 9.3,
    "drivers": [
      { "factor": "New operator (LuckySpins) onboarding", "impact_usd": 8000.00 },
      { "factor": "March Madness sports volume", "impact_usd": 12000.00 },
      { "factor": "Seasonal baseline", "impact_usd": 142000.00 }
    ],
    "by_operator": [
      { "operator_slug": "example-casino", "projected_usd": 52000.00 },
      { "operator_slug": "lucky-spins", "projected_usd": 8000.00 }
    ],
    "series": [
      { "date": "2026-03-20", "projected_usd": 5200.00 },
      { "date": "2026-03-21", "projected_usd": 5400.00 }
    ],
    "generated_at": "2026-03-19T12:00:00Z"
  }
}

Activity Feed

Real-time feed of all significant platform events. Used on the God Mode dashboard to provide an at-a-glance view of what is happening across the platform.

Get Activity Feed

GET/api/internal/activity

Query Parameters

ParamTypeDefaultDescription
limitnumber50Number of events to return. Max 200.
typestringnullFilter: trade, settlement, user_signup, risk_event, operator_event, config_change.
operatorstringnullFilter by operator slug.
cursorstringnullCursor for pagination (returned in previous response).

Response - 200 OK

{
  "data": [
    {
      "id": "act_001",
      "type": "trade",
      "title": "Large trade executed",
      "description": "player_42 bought 200 YES @ $0.62 on 'Will BTC exceed $150k...' ($124.00)",
      "operator_slug": "example-casino",
      "user_id": "usr_xyz",
      "market_id": "mkt_001",
      "severity": "info",
      "metadata": {
        "trade_id": "trd_big1",
        "amount_usd": 124.00,
        "side": "buy",
        "outcome": "yes"
      },
      "created_at": "2026-03-19T11:58:00Z"
    },
    {
      "id": "act_002",
      "type": "risk_event",
      "title": "Circuit breaker armed",
      "description": "Market 'ETH flip BTC' exposure approaching limit (85%)",
      "severity": "warning",
      "metadata": {
        "market_id": "mkt_099",
        "utilization_pct": 85
      },
      "created_at": "2026-03-19T11:55:00Z"
    }
  ],
  "next_cursor": "eyJpZCI6ImFjdF8wNTAifQ=="
}

Analytics

Advanced analytics endpoints for cohort analysis, lifetime value calculations, and behavioral pattern detection. These power the God Mode analytics dashboard.

Cohort Analysis

GET/api/internal/analytics/cohorts

Returns user retention and engagement cohorts grouped by signup week. Each cohort shows the percentage of users still active in subsequent weeks, average trades, and revenue per user.

Query Parameters

ParamTypeDefaultDescription
fromstring12 weeks agoISO 8601 start date for cohort range.
tostringnowISO 8601 end date.
operatorstringnullFilter by operator slug.
granularitystring"week"Cohort grouping: week or month.

Response - 200 OK

{
  "data": {
    "cohorts": [
      {
        "cohort": "2026-W10",
        "signup_count": 420,
        "retention": {
          "week_0": 1.0,
          "week_1": 0.64,
          "week_2": 0.48,
          "week_3": 0.38,
          "week_4": 0.32
        },
        "avg_trades_per_user": 8.4,
        "avg_revenue_per_user_usd": 3.20,
        "avg_volume_per_user_usd": 148.00
      },
      {
        "cohort": "2026-W11",
        "signup_count": 380,
        "retention": {
          "week_0": 1.0,
          "week_1": 0.68,
          "week_2": 0.52
        },
        "avg_trades_per_user": 9.1,
        "avg_revenue_per_user_usd": 3.80,
        "avg_volume_per_user_usd": 162.00
      }
    ],
    "summary": {
      "avg_week_1_retention": 0.66,
      "avg_week_4_retention": 0.32,
      "best_cohort": "2026-W11",
      "worst_cohort": "2026-W08"
    }
  }
}

Lifetime Value

GET/api/internal/analytics/ltv

Returns estimated lifetime value (LTV) segmented by operator, acquisition channel, and user tier. LTV is calculated based on historical revenue per user over their active lifespan.

Query Parameters

ParamTypeDefaultDescription
segmentstring"operator"Segmentation: operator, tier, category.
operatorstringnullFilter by operator slug.

Response - 200 OK

{
  "data": {
    "global_ltv_usd": 15.40,
    "global_ltv_30d_usd": 4.20,
    "segments": [
      {
        "label": "example-casino",
        "user_count": 8420,
        "ltv_usd": 15.25,
        "ltv_30d_usd": 4.10,
        "avg_lifespan_days": 62,
        "avg_trades": 25.5,
        "avg_volume_usd": 294.50
      },
      {
        "label": "lucky-spins",
        "user_count": 2100,
        "ltv_usd": 12.80,
        "ltv_30d_usd": 3.60,
        "avg_lifespan_days": 28,
        "avg_trades": 14.2,
        "avg_volume_usd": 182.00
      }
    ],
    "trend": [
      { "month": "2026-01", "ltv_usd": 14.20 },
      { "month": "2026-02", "ltv_usd": 14.80 },
      { "month": "2026-03", "ltv_usd": 15.40 }
    ]
  }
}

Behavioral Patterns

GET/api/internal/analytics/patterns

Returns detected behavioral patterns across the user base. Includes peak trading hours, popular categories, average session duration, trade frequency distributions, and device/platform breakdown.

Query Parameters

ParamTypeDefaultDescription
fromstring30 days agoISO 8601 start date.
tostringnowISO 8601 end date.
operatorstringnullFilter by operator slug.

Response - 200 OK

{
  "data": {
    "peak_hours_utc": [18, 19, 20, 21],
    "category_distribution": [
      { "category": "sports", "pct": 42.0 },
      { "category": "crypto", "pct": 28.0 },
      { "category": "politics", "pct": 18.0 },
      { "category": "entertainment", "pct": 12.0 }
    ],
    "avg_session_duration_minutes": 14.2,
    "avg_trades_per_session": 3.4,
    "trade_frequency_distribution": {
      "1_per_week": 0.32,
      "2_5_per_week": 0.28,
      "6_10_per_week": 0.22,
      "11_plus_per_week": 0.18
    },
    "device_breakdown": {
      "mobile": 0.68,
      "desktop": 0.28,
      "tablet": 0.04
    },
    "bet_size_distribution": {
      "under_5_usd": 0.35,
      "5_20_usd": 0.38,
      "20_100_usd": 0.20,
      "100_plus_usd": 0.07
    },
    "popular_markets": [
      { "market_id": "mkt_001", "title": "Will BTC exceed $150k...", "trade_count": 12400 }
    ]
  }
}

Configuration

Global platform configuration. Controls risk limits, spread parameters, fee structures, feature flags, and system-wide defaults. Changes are audit-logged with the admin user who made them.

Get Configuration

GET/api/internal/config

Response - 200 OK

{
  "data": {
    "risk": {
      "global_exposure_limit_usd": 500000,
      "category_limits": {
        "sports": 200000,
        "crypto": 150000,
        "politics": 100000,
        "entertainment": 50000
      },
      "per_trade_max_usd": 5000,
      "per_market_max_usd": 50000,
      "circuit_breaker_threshold_pct": 90,
      "sharp_score_threshold": 60,
      "restricted_score_threshold": 80
    },
    "spread": {
      "base_spread_bps": 200,
      "min_spread_bps": 100,
      "max_spread_bps": 800,
      "risk_multiplier": 1.5,
      "volume_discount_enabled": true,
      "volume_discount_threshold_usd": 10000,
      "volume_discount_bps": 25
    },
    "fees": {
      "trading_fee_bps": 50,
      "settlement_fee_bps": 0,
      "withdrawal_fee_usd": 0
    },
    "features": {
      "s2s_enabled": true,
      "embed_enabled": true,
      "auto_settlement": true,
      "sharp_detection": true,
      "revenue_forecast": true,
      "cohort_analytics": true
    },
    "defaults": {
      "operator_revenue_share_pct": 70,
      "user_max_bet_usd": 1000,
      "session_timeout_hours": 8,
      "s2s_retry_max": 5,
      "s2s_retry_backoff_ms": 1000
    },
    "updated_at": "2026-03-18T09:00:00Z",
    "updated_by": "admin_001"
  }
}

Update Configuration

POST/api/internal/config

Updates one or more configuration values. Supports partial updates - only include the keys you want to change. All changes are audit-logged. Some changes (like reducing global exposure limits) may trigger immediate risk re-evaluation.

Caution. Changing risk limits or spread parameters affects all live trading immediately. Consider applying changes during low-volume hours and monitoring the risk dashboard after updates.

Request Body

{
  "risk": {
    "global_exposure_limit_usd": 600000,
    "sharp_score_threshold": 55
  },
  "spread": {
    "base_spread_bps": 250
  },
  "reason": "Increasing global limit for March Madness volume spike"
}

Response - 200 OK

{
  "data": {
    "updated_keys": [
      "risk.global_exposure_limit_usd",
      "risk.sharp_score_threshold",
      "spread.base_spread_bps"
    ],
    "previous_values": {
      "risk.global_exposure_limit_usd": 500000,
      "risk.sharp_score_threshold": 60,
      "spread.base_spread_bps": 200
    },
    "new_values": {
      "risk.global_exposure_limit_usd": 600000,
      "risk.sharp_score_threshold": 55,
      "spread.base_spread_bps": 250
    },
    "audit_id": "aud_cfg_001",
    "updated_by": "admin_001",
    "updated_at": "2026-03-19T12:00:00Z"
  }
}

Reports

Generate on-demand or scheduled reports in CSV, Excel, or PDF format. Reports can cover trades, revenue, users, risk events, or settlements within a specified date range.

Generate Report

POST/api/internal/reports/generate

Request Body

{
  "type": "trades",
  "format": "csv",
  "filters": {
    "operator": "example-casino",
    "from": "2026-03-01T00:00:00Z",
    "to": "2026-03-19T23:59:59Z",
    "min_amount": 10
  },
  "columns": ["id", "user_name", "market_title", "outcome", "side", "price", "quantity", "cost_usd", "fee_usd", "created_at"],
  "delivery": "download"
}
FieldTypeRequiredDescription
typestringYesReport type: trades, revenue, users, risk_events, settlements, invoices.
formatstringYesOutput format: csv, xlsx, pdf.
filtersobjectNoFilter criteria (varies by report type).
columnsstring[]NoSpecific columns to include. Defaults to all available columns.
deliverystringNodownload (default) or email.
emailstringNoRequired if delivery is email.

Response - 200 OK (download)

{
  "data": {
    "report_id": "rpt_001",
    "type": "trades",
    "format": "csv",
    "status": "ready",
    "download_url": "/api/internal/reports/rpt_001/download",
    "expires_at": "2026-03-19T14:00:00Z",
    "row_count": 4280,
    "file_size_bytes": 842000,
    "generated_at": "2026-03-19T12:00:05Z"
  }
}

Scheduled Reports

POST/api/internal/reports/scheduled

Creates a recurring report schedule. Reports are generated automatically at the specified frequency and delivered via email.

Request Body

{
  "name": "Weekly Operator Trade Report",
  "type": "trades",
  "format": "xlsx",
  "frequency": "weekly",
  "day_of_week": 1,
  "time_utc": "08:00",
  "filters": {
    "operator": "example-casino"
  },
  "recipients": ["ops@predictu.com", "reports@example-casino.com"],
  "enabled": true
}

Response - 201 Created

{
  "data": {
    "id": "sched_001",
    "name": "Weekly Operator Trade Report",
    "type": "trades",
    "format": "xlsx",
    "frequency": "weekly",
    "day_of_week": 1,
    "time_utc": "08:00",
    "next_run_at": "2026-03-24T08:00:00Z",
    "recipients": ["ops@predictu.com", "reports@example-casino.com"],
    "enabled": true,
    "created_by": "admin_001",
    "created_at": "2026-03-19T12:00:00Z"
  }
}

Data Export

Bulk data export for specific entity types. Unlike reports (which are filtered and formatted), exports produce raw data dumps suitable for data warehouse ingestion or external analysis.

Export Data

POST/api/internal/export/[type]

Path Parameters

ParamTypeDescription
typestringExport type: users, trades, positions, ledger, settlements, risk_events.

Request Body

{
  "format": "csv",
  "from": "2026-01-01T00:00:00Z",
  "to": "2026-03-19T23:59:59Z",
  "operator": null,
  "include_pii": false,
  "compression": "gzip"
}
FieldTypeDefaultDescription
formatstring"csv"Export format: csv, jsonl, parquet.
fromstringRequiredISO 8601 start date.
tostringRequiredISO 8601 end date.
operatorstringnullFilter by operator slug.
include_piibooleanfalseInclude PII (emails, names). Requires elevated permissions.
compressionstring"none"Compression: none, gzip, zstd.

Response - 202 Accepted

{
  "data": {
    "export_id": "exp_001",
    "type": "trades",
    "format": "csv",
    "status": "processing",
    "estimated_rows": 892000,
    "estimated_size_bytes": 180000000,
    "poll_url": "/api/internal/export/exp_001/status",
    "created_at": "2026-03-19T12:00:00Z"
  }
}
Async processing. Large exports are processed asynchronously. Poll the poll_url for status updates. When status changes to "ready", a download_url will be included in the response. Download links expire after 1 hour.

File Upload

Upload files to the Predictu CDN. Used for operator logos, favicons, market images, and invoice attachments. Returns a CDN URL that can be referenced in subsequent API calls.

Upload File

POST/api/internal/upload

Send the file as multipart/form-data. The Content-Type must bemultipart/form-data - do not use application/json.

Form Fields

FieldTypeRequiredDescription
fileFileYesThe file to upload. Max 5MB. Accepted types: png, jpg, jpeg, svg, webp, pdf.
categorystringYesUpload category: operator_logo, operator_favicon, market_image, invoice_attachment.
operator_slugstringNoAssociate the file with an operator. Required for operator assets.

Response - 200 OK

{
  "data": {
    "id": "file_001",
    "url": "https://cdn.predictu.com/operators/example-casino/logo.png",
    "category": "operator_logo",
    "operator_slug": "example-casino",
    "content_type": "image/png",
    "size_bytes": 24800,
    "width": 512,
    "height": 512,
    "uploaded_by": "admin_001",
    "uploaded_at": "2026-03-19T12:00:00Z"
  }
}

Operator Onboarding

Advance an operator through the onboarding pipeline. The onboarding flow consists of steps:brandings2s_configembed_setuptest_tradesgo_live. Each step validates prerequisites before allowing progression.

Advance Onboarding Step

POST/api/internal/onboarding/[operatorId]

Path Parameters

ParamTypeDescription
operatorIdstringOperator ID (e.g. op_abc123).

Request Body

{
  "action": "advance",
  "step": "s2s_config",
  "data": {
    "callback_url": "https://api.luckyspins.com/predictu/callback",
    "signing_key_confirmed": true,
    "test_callback_success": true
  },
  "notes": "S2S callback verified with test transaction"
}
FieldTypeRequiredDescription
actionstringYesAction: advance (move to next step), rollback (go back one step), skip (skip optional step).
stepstringYesCurrent step being completed.
dataobjectNoStep-specific data to validate and persist.
notesstringNoAdmin notes for the onboarding audit trail.

Response - 200 OK

{
  "data": {
    "operator_id": "op_xyz789",
    "current_step": "embed_setup",
    "previous_step": "s2s_config",
    "completed_steps": ["branding", "s2s_config"],
    "remaining_steps": ["embed_setup", "test_trades", "go_live"],
    "status": "configuring",
    "progress_pct": 40,
    "notes": "S2S callback verified with test transaction",
    "updated_by": "admin_001",
    "updated_at": "2026-03-19T12:00:00Z"
  }
}
Validation. The go_live step requires all previous steps to be completed and at least one successful test trade to have been executed through the S2S pipeline. Attempting to advance togo_live without meeting prerequisites returns a 422 with a list of unmet requirements.

Pagination

All list endpoints use offset-based pagination with a consistent response envelope. The activity feed uses cursor-based pagination for real-time consistency.

Offset Pagination

// Request
GET /api/internal/trades?page=2&limit=50

// Response envelope
{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 50,
    "total": 892310,
    "total_pages": 17847
  }
}

Cursor Pagination

// Request
GET /api/internal/activity?limit=50&cursor=eyJpZCI6ImFjdF8wNTAifQ==

// Response envelope
{
  "data": [...],
  "next_cursor": "eyJpZCI6ImFjdF8xMDAifQ=="
}
Rate limits. Admin API endpoints are rate-limited to 60 requests per minute per admin user. The X-RateLimit-Remaining and X-RateLimit-Reset headers are included in every response. Exceeding the limit returns 429 Too Many Requests.