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.
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"])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.
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/meKeys use the np_live_ prefix. The full key is shown once on generation — save it immediately. Revoke and regenerate anytime from Settings.
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 a single signal. Timestamp is locked server-side at the moment of receipt.
| Parameter | Required | Type | Description |
|---|---|---|---|
| strategy_id | Yes | string | Strategy UUID from GET /me |
| market | Yes | string | Kalshi ticker or Polymarket conditionId |
| direction | Yes | string | "YES" or "NO" |
| size | Yes | number | Position size |
| size_type | No | string | "dollars" (default) or "contracts" |
| entry_price | No | number | Entry price (0-1). Auto-fetched if omitted. |
| exchange | No | string | "kalshi" or "polymarket". Required if strategy supports both. |
| rationale | No | string | Trade rationale. Visible to subscribers. |
| idempotency_key | No | string | Prevents 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']}"){
"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"
}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},
]
}
){
"results": [
{"index": 0, "status": "registered", "signal_id": "...", "timestamp": "..."},
{"index": 1, "status": "registered", "signal_id": "...", "timestamp": "..."}
],
"summary": {"registered": 2, "failed": 0}
}List your signals with optional filters.
| Parameter | Required | Type | Description |
|---|---|---|---|
| strategy_id | No | string | Filter by strategy |
| status | No | string | registered, matched, win, loss, push |
| limit | No | number | Max results (default 20, max 100) |
| offset | No | number | Pagination 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 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-6f99a534bcb3All errors return a consistent format:
{
"error": {
"code": "market_not_found",
"message": "Could not resolve market ticker",
"field": "market"
}
}| Code | Status | What to do |
|---|---|---|
| unauthorized | 401 | Check your API key is valid and active |
| missing_required_field | 400 | Include the indicated field |
| invalid_direction | 400 | Must be "YES" or "NO" |
| market_not_found | 400 | Check the ticker or market name |
| strategy_not_found | 404 | Check strategy_id from GET /me |
| strategy_exchange_mismatch | 400 | Signal exchange must match strategy |
| duplicate_signal | 409 | Safe to ignore — idempotency key already used |
| rate_limit_exceeded | 429 | Wait and retry. 100 signals/hour limit. |
X-RateLimit-Remaining header shows your remaining quota on each response.