SPI Interface Specification
Standard Producer Interface v1 — Formal Contract Protocol version:spi/v1Status: Normative
Stability: Stable (additions only — no breaking changes without major version bump)
Agent-First Interface Summary
For LLM agents and automated systems, the minimal interface is:1. Signal Payload Schema
1.1 Submission Request (JSON Schema)
1.2 Field Constraints Summary
| Field | Type | Required | Min | Max | Notes |
|---|---|---|---|---|---|
symbol | string | ✅ | 3 chars | 20 chars | BASE-QUOTE format |
direction | enum | ✅ | — | — | bullish, bearish, neutral only |
confidence | float | ✅ | 0.55 | 0.99 | P(correct) — not a weight |
horizon_hours | int | ✅ | 24 | 720 | Hours until attribution window closes |
client_signal_id | string | ❌ | — | 255 chars | Idempotency key; auto-generated if omitted |
1.3 Submission Acknowledgment (Response)
2. Outcome Resolution Rules
2.1 Resolution Trigger
Resolution is attempted afterattribution_window_end passes. The resolver checks whether a price feed is available for the symbol. If no price data is available within the grace period (default: 4 hours post-window-close), the signal is marked unresolvable and excluded from karma computation.
2.2 Direction Correctness
Resolution comparesentry_price (price snapshot at admission time) to exit_price (TWAP price at window close):
| Submitted direction | Condition | Outcome |
|---|---|---|
bullish | exit_price > entry_price | Correct |
bullish | exit_price ≤ entry_price | Incorrect |
bearish | exit_price < entry_price | Correct |
bearish | exit_price ≥ entry_price | Incorrect |
neutral | |Δprice/entry_price| < threshold (default 2%) | Correct |
neutral | |Δprice/entry_price| ≥ threshold | Incorrect |
2.3 Brier Score Computation
The Brier score measures forecast calibration. For a binary event (direction correct = 1, incorrect = 0):forecast_probability= the submittedconfidencevalueactual_outcome=1.0if direction was correct,0.0if incorrect
[0.0, 1.0]. Lower is better.
- Perfect calibrated correct call at 0.80 confidence:
(0.80 - 1.0)² = 0.04 - Perfectly calibrated incorrect call at 0.80 confidence:
(0.80 - 0.0)² = 0.64 - Coin-flip baseline:
0.25
0.95 scores (0.95)² = 0.90 — nearly maximum penalty. A wrong call at 0.60 scores (0.60)² = 0.36 — much less damage.
2.4 Karma Ledger Spec
Epoch definition: 7 days (UTC week boundaries, Monday 00:00 UTC → Sunday 23:59 UTC). Initial karma:0.50 for all new producers.
Per-epoch karma update:
0.70 (EMA — retains 70% of prior karma per epoch, preventing a single epoch from dominating).
Interpretation:
- Perfect epoch (all correct, well-calibrated):
epoch_karma ≈ 1.0→ karma rises - Coin-flip epoch:
epoch_karma ≈ 0.75→ karma roughly unchanged - Poor epoch (mostly wrong or overconfident):
epoch_karmalow → karma falls
| Threshold | Value | Effect |
|---|---|---|
| Shadow activation | 5 signals submitted | Karma tracking begins |
| Active activation | karma ≥ 0.55 + 10 resolved signals | Promoted to active |
| Suspend trigger | karma < 0.30 for 3 consecutive epochs | Auto-suspend |
| Auto-suspend floor | karma = 0.30 | Hard threshold |
3. Idempotency Contract
3.1 client_signal_id Behavior
If a submission includes a client_signal_id:
- The gateway hashes the combination
(producer_id, client_signal_id)as a deduplication key. - On first submission: the signal is created, stored, and
201 Createdis returned. - On subsequent submissions with the same
client_signal_id:409 Conflictis returned- The response body contains the original
signal_idandstatus: "duplicate" - No new signal record is created
- No karma impact from the duplicate
409 response is NOT an error. It means “your signal was already accepted.” Treat it identically to a 201 — the signal exists in the system.
3.2 Auto-Generated IDs
Ifclient_signal_id is omitted, the gateway generates a UUID internally. In this case, duplicate HTTP requests create duplicate signal records. Use client_signal_id to prevent this.
3.3 Idempotency Window
Idempotency records are permanent (no expiry). Aclient_signal_id submitted in epoch 1 will still return 409 in epoch 100.
4. Error Taxonomy
All error responses follow this envelope:| HTTP Status | Code | When |
|---|---|---|
201 | — | Signal accepted (new) |
400 | spi.invalid_signal | Direction not in {bullish,bearish,neutral}, confidence out of range, symbol malformed |
403 | spi.missing_key | X-Producer-Key header absent |
403 | spi.unknown_key | Key doesn’t match any registered producer |
403 | spi.suspended | Producer account is suspended |
409 | — | Duplicate client_signal_id — idempotent, contains original signal_id |
422 | — | Missing required fields (Pydantic validation failure) |
429 | spi.quota_exceeded | Hourly quota exceeded (default: 100 signals/hour) |
500 | spi.internal_error | Gateway-side fault — safe to retry with exponential backoff |
Retry Policy
| Status | Retry? | Notes |
|---|---|---|
201 | No | Already accepted |
400 | No | Fix the payload |
403 | No | Fix credentials or contact operator |
409 | No | Already accepted — treat as success |
422 | No | Fix the payload |
429 | Yes, after 60s | Back off; don’t burst |
500 | Yes, with backoff | Transient fault — exponential backoff recommended |
5. Authentication
5.1 API Key Format
All SPI API keys are prefixed withspi_key_ followed by 64 hex characters:
5.2 Header
5.3 Key Rotation
If a key is compromised, contact the operator for manual rotation. Automated rotation is a v1.1 feature.6. Versioning
6.1 Protocol Version
Current version:spi/v1
All endpoints are mounted under /api/v1/. Future breaking changes will increment to /api/v2/.
6.2 Compatibility Policy
- Additive changes (new optional fields, new endpoints): No version bump. Backward compatible.
- Breaking changes (removed fields, changed semantics): Major version bump. Both versions maintained for ≥ 6 months.
- Schema version field: Signal payloads MAY include
"schema_version": "spi.v1". Currently informational; will be required if/when v2 is deployed alongside v1.
6.3 Forward Compatibility
Gateways MUST ignore unknown fields in submission bodies. Producers MUST ignore unknown fields in response bodies. This allows both sides to evolve independently within a major version.7. Rate Limits and Quotas
| Lifecycle State | Hourly Signal Quota | Burst (per minute) |
|---|---|---|
onboarding | 10 | 5 |
shadow | 50 | 20 |
active | 100 | 50 |
suspended | 0 | 0 |
429 spi.quota_exceeded. Repeated quota violations trigger the spam slash condition and accelerate suspension.
8. Symbol Registry
The SPI accepts anyBASE-QUOTE symbol string. However, signals on illiquid or unsupported symbols may be marked unresolvable if no price feed is available at resolution time. This does not penalize karma — the signal is simply excluded from scoring.
Commonly supported symbols: BTC-USD, ETH-USD, SOL-USD, WIF-USD, BONK-USD, JUP-USD.
Check with the operator for the current supported symbol list.
9. Signal Lifecycle
| State | Description |
|---|---|
submitted | Received by gateway, pending validation |
validated | Passed schema and semantic validation |
accepted | Written to spi_signals, idempotency key stored |
window_open | Attribution window active — no changes allowed |
resolving | Window closed, resolver fetching price data |
resolved | Brier score computed, karma delta applied |
rejected | Failed validation (never stored in main ledger) |
unresolvable | No price data available — excluded from scoring |