API Reference

OPTIONAL

Most PMs register signals through the NextProd dashboard — no code required. The API is for PMs who want to automate signal registration from their own trading systems or models. Same trust guarantee either way — server-generated timestamps, immutable records.

Quick Start

The entire integration in one code block. Register a signal before you trade, just like the UI — but from your model.

import requests

NEXTPROD_API_KEY = "np_live_your_api_key_here"

def register_signal(strategy_id, market, direction, size):
    response = requests.post(
        "https://nextprodapp.com/api/v1/signals",
        headers={"Authorization": f"Bearer {NEXTPROD_API_KEY}"},
        json={
            "strategy_id": strategy_id,
            "market": market,
            "direction": direction,
            "size": size
        }
    )
    return response.json()

# Example: register a YES signal on an MLB game
result = register_signal(
    strategy_id="your_strategy_id",
    market="KXMLBGAME-26APR041905MIANYY-NYY",
    direction="YES",
    size=300
)
print(result["signal_id"], result["timestamp"])

Where It Sits in Your Workflow

model.run()
nextprod.register()
exchange.execute()

One API call between your model output and your exchange execution. Non-blocking. The timestamp is locked server-side the moment the request hits our servers.

Authentication

All API requests require a Bearer token in the Authorization header. Generate your key in Settings → Exchanges.

curl -H "Authorization: Bearer np_live_your_api_key_here" \
  https://nextprodapp.com/api/v1/me

Keys use the np_live_ prefix. The full key is shown once on generation — save it immediately. Revoke and regenerate anytime from Settings.

Verify Your Key

GET/api/v1/me

Returns your PM profile and active strategies. Use this to verify your key works and get strategy IDs.

curl -H "Authorization: Bearer np_live_your_api_key_here" \
  https://nextprodapp.com/api/v1/me
{
  "pm_id": "847b0d6c-...",
  "name": "Your Name",
  "strategies": [
    {
      "strategy_id": "your_strategy_id",
      "name": "MLB Moneyline Momentum",
      "exchange": "kalshi",
      "signal_count": 42,
      "subscriber_count": 3
    }
  ]
}

Register Signal

POST/api/v1/signals

Register a single signal. Timestamp is locked server-side at the moment of receipt.

ParameterRequiredTypeDescription
strategy_idYesstringStrategy UUID from GET /me
marketYesstringKalshi ticker or Polymarket conditionId
directionYesstring"YES" or "NO"
sizeYesnumberPosition size
size_typeNostring"dollars" (default) or "contracts"
entry_priceNonumberEntry price (0-1). Auto-fetched if omitted.
exchangeNostring"kalshi" or "polymarket". Required if strategy supports both.
rationaleNostringTrade rationale. Visible to subscribers.
idempotency_keyNostringPrevents duplicate signals on retry.
import requests

response = requests.post(
    "https://nextprodapp.com/api/v1/signals",
    headers={"Authorization": f"Bearer {NEXTPROD_API_KEY}"},
    json={
        "strategy_id": "your_strategy_id",
        "market": "KXMLBGAME-26APR041905MIANYY-NYY",
        "direction": "YES",
        "size": 300,
        "entry_price": 0.45,
        "rationale": "Model triggered on momentum signal"
    }
)

data = response.json()
print(f"Signal {data['signal_id']} registered at {data['timestamp']}")
Response:
{
  "signal_id": "629229ed-...",
  "timestamp": "2026-04-04T19:12:07.572Z",
  "status": "registered",
  "market_resolved": "KXMLBGAME-26APR041905MIANYY-NYY",
  "entry_price": 0.45,
  "size_usd": 300,
  "direction": "YES",
  "exchange": "KALSHI"
}

Batch Register

POST/api/v1/signals/batch

Register up to 50 signals at once. Each processed independently — one failure doesn't block the rest.

response = requests.post(
    "https://nextprodapp.com/api/v1/signals/batch",
    headers={"Authorization": f"Bearer {NEXTPROD_API_KEY}"},
    json={
        "signals": [
            {"strategy_id": "your_strategy_id", "market": "KXMLBGAME-...-NYY", "direction": "YES", "size": 300},
            {"strategy_id": "your_strategy_id", "market": "KXMLBGAME-...-BOS", "direction": "NO", "size": 150},
        ]
    }
)
Response:
{
  "results": [
    {"index": 0, "status": "registered", "signal_id": "...", "timestamp": "..."},
    {"index": 1, "status": "registered", "signal_id": "...", "timestamp": "..."}
  ],
  "summary": {"registered": 2, "failed": 0}
}

List Signals

GET/api/v1/signals

List your signals with optional filters.

ParameterRequiredTypeDescription
strategy_idNostringFilter by strategy
statusNostringregistered, matched, win, loss, push
limitNonumberMax results (default 20, max 100)
offsetNonumberPagination offset
curl -H "Authorization: Bearer np_live_your_api_key_here" \
  "https://nextprodapp.com/api/v1/signals?strategy_id=your_strategy_id&status=win&limit=10"

Get Signal

GET/api/v1/signals/:signal_id

Get detailed status of a single signal. Use for polling after registration.

curl -H "Authorization: Bearer np_live_your_api_key_here" \
  https://nextprodapp.com/api/v1/signals/629229ed-2328-46a7-a9ee-6f99a534bcb3

Errors

All errors return a consistent format:

{
  "error": {
    "code": "market_not_found",
    "message": "Could not resolve market ticker",
    "field": "market"
  }
}
CodeStatusWhat to do
unauthorized401Check your API key is valid and active
missing_required_field400Include the indicated field
invalid_direction400Must be "YES" or "NO"
market_not_found400Check the ticker or market name
strategy_not_found404Check strategy_id from GET /me
strategy_exchange_mismatch400Signal exchange must match strategy
duplicate_signal409Safe to ignore — idempotency key already used
rate_limit_exceeded429Wait and retry. 100 signals/hour limit.
Rate limits
100 signal registrations per hour per API key. The X-RateLimit-Remaining header shows your remaining quota on each response.