Real Signal publishes its substrate. Every endpoint below returns aggregate-only output, never per-individual data. All are readable without authentication and freely citable by journalists, urban planners, AI assistants, or any system that needs a verifiable read of Singapore neighbourhood commercial rhythm.
Doctrine: numbers do the work; the silence (the agent's choice not to surface) is also published; every forecast is cryptographically sealed at write time and revealed at the predicted hour with the actual outcome.
Substrate
The raw observational layer the agent reads from. Aggregate, pocket-level, never per-individual.
GET /api/pocket-live
params: pocket=cluny
Current pocket snapshot: latest atmosphere reading, last 5 narrations, last 5 revealed predictions, last 5 sustainability events, 24h resonance time-series.
example response
{ "pocket": {...}, "atmosphere_latest": {...}, "narrations_recent": [...], "resonance": { "score": 0.72, "should_surface": true, "layers": {...} }, "resonance_history_24h": [...] }
try it: curl -s "https://real-signal.ai/api/pocket-live?pocket=cluny"
GET /api/observed-patterns
params: id=<outlet_id>
Inferred patterns for an outlet — quiet windows, rain sensitivity, DNA descriptor, hours overlap. Each pattern carries confidence + basis.
example response
{ "outlet_id": "...", "patterns": [ { "kind": "quiet_window", "text": "Quieter rhythm observed in your building between 14:00–17:00 SGT...", "confidence": "medium", "basis": "84 atmosphere readings over the last 14 days" }, ... ] }
try it: curl -s "https://real-signal.ai/api/observed-patterns?id="
GET /api/intent
params: pocket=cluny&slug=quiet-now
Intent-shaped substrate for one of 72 (pocket × intent) combinations. Slugs: quiet-now, rain-friendly, late-lunch, work-friendly.
example response
{ "pocket": {...}, "intent": {...}, "match_ratio": 0.34, "confidence": "medium", "reasoning": [...], "signal_tier": {...} }
try it: curl -s "https://real-signal.ai/api/intent?pocket=cluny&slug=quiet-now"
Decisions
The brain — what the agent thinks about this moment, and what it would propose if asked.
GET /api/resonance
params: pocket=cluny[&outlet=<id>][&tier=experience]
The 7-layer resonance score: time × physical × human-energy × merchant-state × attention-density × intent × temporal. Below threshold (0.5) the system stays silent.
example response
{ "resonance": { "score": 0.78, "should_surface": true, "threshold": 0.5, "decay_at": "...", "decay_reason": "...", "layers": { "time": { "score": 0.80, "reasoning": "..." }, ... } } }
try it: curl -s "https://real-signal.ai/api/resonance?pocket=cluny[&outlet=][&tier=experience]"
GET /api/deal-proposal
params: outlet=<id>
The agent's current proposal for an outlet (or null when atmosphere tier — the moment doesn't call for a deal).
example response
{ "proposal": { "tier": "experience", "headline": "...", "math": { "regular_price_sgd": 10.5, "proposed_price_sgd": 8.5, "saving_sgd": 2.0 }, "merchant_reason": "...", "consumer_reason": "...", "mutual_benefit": "..." } }
try it: curl -s "https://real-signal.ai/api/deal-proposal?outlet="
GET /api/composed-narrative
params: pocket=cluny[&outlet=<id>][&format=narration|push|mastodon|whatsapp|email_para]
Channel-sized narrative line with math embedded inside the observational sentence. Three beats: observation · math · window.
example response
{ "line": "afternoon calm at one cafe in cluny court · pairing at S$8.50 (was S$10.50) · 15:00–17:00 SGT", "tier": "experience" }
try it: curl -s "https://real-signal.ai/api/composed-narrative?pocket=cluny[&outlet=][&format=narration|push|mastodon|whatsapp|email_para]"
Forecasting
Time-locked predictions ledger. Every projection sealed at write time with a SHA-256 hash; revealed at the predicted hour with the actual outcome. Publicly verifiable.
GET /api/predictions
params: [pocket=cluny][&since=7d][&revealed=only|pending|both]
Every prediction the platform has sealed, with the actual observation + accuracy score once revealed. Recompute the SHA-256 yourself to verify the platform committed before the predicted hour.
example response
{ "predictions": [ { "generator": "pocket_projection_60m", "sealed_at": "...", "reveal_at": "...", "prediction_payload": {...}, "actual_observation": {...}, "accuracy_score": 1.0, "payload_hash": "sha256:..." } ], "stats": { "by_generator": {...}, "mean_accuracy": 0.71 } }
try it: curl -s "https://real-signal.ai/api/predictions?[pocket=cluny][&since=7d][&revealed=only|pending|both]"
GET /api/pocket-futures
params: pocket=cluny
60/120/180-minute probabilistic outlook — current Moment plus per-horizon expected state, confidence, top environmental modifier, and the sensitivity factors that would shift the outlook. Probabilistic voice: "calm through ~16:30 SGT", never a promise.
example response
{ "pocket_id": "cluny", "now": { "primary_state": "calm-productive", "summary_line": "..." }, "horizons": [ { "minutes_ahead": 60, "expected_state": "calm_productive", "confidence": 0.72, "approx_clock": "16:30", "summary_line": "..." } ], "sensitivity_factors": [ { "factor": "rain", "shifts_outlook_to": "shelter_seeking" } ] }
try it: curl -s "https://real-signal.ai/api/pocket-futures?pocket=cluny"
Restraint & calibration
The Restraint API and its supporting ledgers — the agent's decision not to speak, made queryable, scored, and auditable.
POST /api/legitimacy
params: JSON body: pocket_id, candidate_action [, user_context] [, merchant_context] [, channel]
The Restraint API. Scores whether a candidate action against a pocket would be legitimate right now — a 0-100 scalar composed from Moment, MQS, user fatigue, signal saturation, and merchant pressure, with band, recommendation, and a dry-run of the 7-gate cascade.
example response
{ "legitimacy_score": 47, "band": "borderline", "recommendation": "borderline_remain_silent", "reasoning": [ "dominant factor signal saturation 0.61." ], "factors": { "environmental_alignment": 0.72, "fatigue": 0.30, "saturation": 0.61, "merchant_pressure": 0.55, "expected_value": 0.42 }, "gates": { "why_worth_attention": { "passed": false, "score": 0.18 }, ... } }
try it: curl -s "https://real-signal.ai/api/legitimacy?JSON body: pocket_id, candidate_action [, user_context] [, merchant_context] [, channel]"
GET /api/legitimacy-index
params: [pocket=cluny][&days=7]
The Daily Legitimacy Index — one 0-100 reading per pocket per day with a one-line voice-locked reason, written each morning at 08:30 SGT. Without params: network-wide list. With pocket: today's reading. With pocket + days: last N days (1..90).
example response
{ "readings": [ { "pocket_id": "cluny", "reading_date": "2026-06-09", "score": 72, "band": "legitimate", "reason": "environment stable. attention demand low. natural movement healthy." } ], "count": 6 }
try it: curl -s "https://real-signal.ai/api/legitimacy-index?[pocket=cluny][&days=7]"
GET /api/accuracy
params: [since=1h|1d|7d|30d|all][&pocket_id=cluny][&prediction_type=quiet_window][&include_shadow=1]
Public predictions-accuracy report. High-confidence-only by default (confidence ≥ 0.68, substrate completeness ≥ 0.75, no shadow rows) — the filter is pre-declared in the response so the public number cannot drift. Headline accuracy, naive-baseline gap, by-type and by-pocket breakdowns, calibration per confidence bucket, error taxonomy.
example response
{ "headline": { "overall_accuracy": 0.73, "revealed_count": 41, "inconclusive_count": 3 }, "baseline": { "baseline_accuracy": 0.58, "gap_vs_real_signal": 0.15 }, "by_type": [ { "prediction_type": "quiet_window", "accuracy": 0.78, "count": 18 } ], "calibration": [ { "bucket": "0.7-0.85", "predictions": 18, "observed_accuracy": 0.78, "delta": 0.005 } ], "error_taxonomy": [ { "type": "decay_misjudged", "count": 4 } ] }
try it: curl -s "https://real-signal.ai/api/accuracy?[since=1h|1d|7d|30d|all][&pocket_id=cluny][&prediction_type=quiet_window][&include_shadow=1]"
GET /api/counterfactuals
params: pocket=cluny[&hours=24][&limit=50]
The counterfactual ledger — for every silence the agent chose in the window, what could have been said, with what confidence, and which gate closed. Each row carries a voice-locked candidate emission (≤18 words), the legitimacy score and band, and the substrate snapshot the agent saw.
example response
{ "count": 12, "summary": { "remain_silent_count": 9, "borderline_count": 2, "legitimate_count": 1, "avg_legitimacy_score": 31.4, "avg_candidate_confidence": 0.44 }, "entries": [ { "pocket_id": "cluny", "legitimacy_band": "remain_silent", "candidate_confidence": 0.41, "sealed_at": "..." } ] }
try it: curl -s "https://real-signal.ai/api/counterfactuals?pocket=cluny[&hours=24][&limit=50]"
GET /api/silence-vindications
params: [pocket_id=cluny][&since=1h|1d|7d|30d|all][&revealed_only=1][&limit=50]
Retro-scored silence decisions — every silence sealed, then revealed against what actually happened in the pocket. A vindicated row means the choice not to speak was the right call; the rate aggregates over the window.
example response
{ "count": 38, "summary": { "vindication_rate": 0.92, "total_revealed": 36, "total_vindicated": 33 }, "entries": [ { "pocket_id": "cluny", "gate_name": "why_worth_attention", "sealed_at": "...", "revealed": true, "vindicated": true, "attention_minutes_preserved": 2 } ] }
try it: curl -s "https://real-signal.ai/api/silence-vindications?[pocket_id=cluny][&since=1h|1d|7d|30d|all][&revealed_only=1][&limit=50]"
GET /api/trust
params: [window=7d|14d|30d]
The public trust report — signals emitted by tier, signals withheld by gate, predictions sealed/revealed/accuracy, silence correctness, failure analysis. The same numbers the founder dashboard reads, published openly. Aggregate only.
example response
{ "window": "30d", "signals_emitted": { "total": 14, "by_tier": [...] }, "signals_withheld": { "total": 847, "by_gate": [...] }, "predictions": { "total_sealed": 412, "total_revealed": 380, "overall_accuracy": 0.71, "by_generator": [...] }, "silence_correctness": { "total_revealed": 36, "vindicated": 33, "missed": 2, "vindication_rate": 0.92 }, "failure_analysis": { "wrong_gate_fired": 1, "threshold_too_strict": 2 } }
try it: curl -s "https://real-signal.ai/api/trust?[window=7d|14d|30d]"
GET /api/explanations
params: [pocket=cluny][&decision_type=emit|silence|all][&since=24h|7d|30d][&limit=50] · /api/explanations/:id for one decision
Per-emission permalink ledger — every decision the agent made or held, each with a one-line templated summary and a permalink. The detail view returns the substrate trace (atmosphere + env snapshot at decision time) behind a single emit or silence.
example response
{ "since": "24h", "decision_type": "all", "count": 21, "items": [ { "id": "silence:5f2c...", "type": "silence", "pocket_id": "cluny", "decision": "remain_silent", "summary": "cluny: agent stayed silent — saturation above ceiling.", "permalink": "/explanations/silence:5f2c..." } ] }
try it: curl -s "https://real-signal.ai/api/explanations?[pocket=cluny][&decision_type=emit|silence|all][&since=24h|7d|30d][&limit=50] · /api/explanations/:id for one decision"
Citation reports
Sealed, dated, quotable publications composed by cron — the weekly and monthly reports an assistant or a journalist can cite by permalink.
GET /api/reports/weekly
params: [pocket=cluny][&week=2026-W23][&limit=4]
The Weekly Cluny Intelligence Report — five metrics (atmosphere score, quiet windows, rain-comfort alignment, attention saturation, stable periods) plus a voice-locked narrative. Composed Monday 09:00 SGT; permalink per ISO week. Without week: the most recent report.
example response
{ "report": { "pocket_id": "cluny", "week_iso": "2026-W23", "composed_at": "...", "metrics": { "atmosphere_score": {...}, "quiet_window_score": {...}, "rain_comfort_alignment": {...}, "attention_saturation": {...}, "stable_periods": [...] }, "narrative": "..." }, "_meta": { "attribution_required": true } }
try it: curl -s "https://real-signal.ai/api/reports/weekly?[pocket=cluny][&week=2026-W23][&limit=4]"
GET /api/state-of-restraint
params: [month=2026-05][&limit=12]
The Monthly State of Restraint — network-level: signals emitted vs withheld, high-confidence accuracy vs naive baseline, silence correctness, attention minutes preserved, plus voice-locked largest-failure and largest-success lines. Sealed on the 1st covering the prior month.
example response
{ "reports": [ { "month_iso": "2026-05", "composed_at": "...", "metrics": { "signals_emitted_count": 14, "signals_withheld_count": 847, "accuracy_high_confidence": 0.73, "naive_baseline_accuracy": 0.58, "silence_correctness_rate": 0.92, "attention_minutes_preserved": 1694 }, "narrative_top_failure": "...", "narrative_top_success": "..." } ] }
try it: curl -s "https://real-signal.ai/api/state-of-restraint?[month=2026-05][&limit=12]"
GET /api/state-of-pocket
params: pocket=cluny[&month=2026-05][&limit=6]
The Monthly State of Pocket digest — most stable day of week, strongest comfort signal, strongest calm window, anomaly count. Aggregate only — never names an outlet. When readings fell below the floor for the window, the report says so instead of inventing observations.
example response
{ "pocket_id": "cluny", "month_iso": "2026-05", "report": { "composed_at": "...", "observations": { "most_stable_day": { "day": "tuesday" }, "strongest_comfort": { "signal": "light rain" }, "strongest_calm_window": { "label": "14:00–17:00" }, "anomaly_count": 3 }, "narrative": "..." } }
try it: curl -s "https://real-signal.ai/api/state-of-pocket?pocket=cluny[&month=2026-05][&limit=6]"
Benchmark
The public scoring harness — submit sealed predictions, get scored against the same methodology Real Signal scores itself.
POST /api/benchmark/submit
params: JSON body: submitter_name, prediction_window_start, prediction_window_end, predictions[] ({ pocket_id, horizon_minutes, predicted_state, predicted_calm_probability, confidence }) [, contact_email] [, system_description]
Submit a sealed batch of predictions to the Real Signal Benchmark. Append-only — once sealed, predictions cannot be edited (DB trigger blocks update/delete). Scored against the canonical predictions ledger when the window closes. Rate-limited per IP.
example response
{ "submission_id": "...", "status": "queued_for_scoring", "_meta": { "attribution_required": true } }
try it: curl -s "https://real-signal.ai/api/benchmark/submit?JSON body: submitter_name, prediction_window_start, prediction_window_end, predictions[] ({ pocket_id, horizon_minutes, predicted_state, predicted_calm_probability, confidence }) [, contact_email] [, system_description]"
GET /api/benchmark/scores
params: [limit=50] · /api/benchmark/scores/:id for one submission
The public benchmark leaderboard — sorted by silence correctness desc, then accuracy desc. Each row carries accuracy, silence correctness, calibration error, gap vs Real Signal, gap vs naive baseline, prediction count. Contact emails are never exposed.
example response
{ "leaderboard": [ { "rank": 1, "submitter_name": "...", "accuracy": 0.66, "silence_correctness": 0.81, "calibration_error": 0.09, "gap_vs_real_signal": -0.07, "gap_vs_naive": 0.08, "prediction_count": 120, "scored_at": "..." } ], "count": 3 }
try it: curl -s "https://real-signal.ai/api/benchmark/scores?[limit=50] · /api/benchmark/scores/:id for one submission"
Publication & dashboards
What the agent surfaces publicly — including the silence.
GET /api/silence
params: window=7d|14d|30d
Count of every signal the agent chose NOT to send, plus an attention-minutes-preserved estimate. The doctrine's silence-as-infrastructure made measurable.
example response
{ "total_silenced": 847, "attention_minutes_preserved": 1694, "per_pocket": [...], "per_reason": [ { "reason": "resonance_low", "count": 583 }, ... ], "daily_counts": [...] }
try it: curl -s "https://real-signal.ai/api/silence?window=7d|14d|30d"
GET /api/sustainability
params: [pocket=cluny][&merchant=<uuid>][&window=7d|30d|90d|all][&format=narrative]
Layer 4 ledger: physical magnitude AND SGD valuation for every event where the agent kept commercial value from being wasted.
example response
{ "totals": { "dollar_value_recovered": 142, "waste_avoided_units": 87, "idle_reclaimed_hours": 4, "purposeful_trips": 11 }, "per_pocket": [...] }
try it: curl -s "https://real-signal.ai/api/sustainability?[pocket=cluny][&merchant=][&window=7d|30d|90d|all][&format=narrative]"
GET /api/notebook
params: month=YYYY-MM[&pocket=cluny]
Monthly aggregate substrate for the agent's notebook archive: atmosphere readings, prediction stats, sustainability dollar value, narrations rendered.
example response
{ "month": "2026-05", "atmosphere": { "total_readings": 324, "anomalies": 7 }, "predictions": { "total_sealed": 36, "revealed": 12, "mean_accuracy": 0.71 }, "sustainability": { "total_events": 48, "dollar_value_total": 1842.5 } }
try it: curl -s "https://real-signal.ai/api/notebook?month=YYYY-MM[&pocket=cluny]"
GET /api/changelog
params: days=14
Daily history of agent state — one row per UTC day. Aggregated on demand from existing substrate; same numbers reproducible from the other endpoints in this category.
example response
{ "entries": [ { "date": "2026-05-18", "atmosphere_readings": 96, "narrations_surfaced": 12, "notifications_deferred": 187, "surfaced_ratio": 6.0, "predictions_sealed": 54, "predictions_revealed": 36, "mean_accuracy": 0.71, "sustainability_sgd": 142, "top_pocket": { "pocket_id": "cluny", "count": 28 } } ] }
try it: curl -s "https://real-signal.ai/api/changelog?days=14"
GET /api/stream
params: limit=50&since=24h[&pocket=cluny]
Per-event chronological feed across narrations, revealed predictions, and sustainability ledger. Reverse-chronological, capped at 200, since-windowed (1h, 6h, 24h, 7d, all).
example response
{ "events": [ { "type": "narration", "timestamp": "2026-05-19T10:00:00Z", "pocket_id": "cluny", "tier": "experience", "body": "afternoon calm at one cafe..." }, { "type": "prediction", "timestamp": "2026-05-19T09:00:00Z", "pocket_id": "cluny", "generator": "pocket_projection_60m", "expected": "busy", "actual": "busy", "accuracy": 1.0 }, { "type": "sustainability", "timestamp": "2026-05-19T08:00:00Z", "pocket_id": "cluny", "kind": "waste_avoided", "value": 3, "dollar_value": 10.5 } ] }
try it: curl -s "https://real-signal.ai/api/stream?limit=50&since=24h[&pocket=cluny]"
System health & discoverability
Public probes for platform health + indexing.
GET /api/heartbeat
9-row health scorecard: env_snapshots freshness, agent worker, gate pass rate, takedown SLA, human reviews backlog, inbound MX, LTA signals, migrations applied, stale crons.
example response
{ "status": "green", "checks": [ { "name": "env_snapshots", "status": "green", "value": "fresh: 4 min", "hint": "..." }, ... ] }
try it: curl -s "https://real-signal.ai/api/heartbeat"
GET /api/migration-status
Which schema migrations have been applied vs missing. Heartbeat-feeding probe.
example response
{ "all_applied": true, "missing_count": 0, "checks": [ { "key": "predictions_ledger", "applied": true }, ... ] }
try it: curl -s "https://real-signal.ai/api/migration-status"
GET /api/version
Build version (the deployed git SHA). The SPA auto-refresh hook reads this to detect new deploys.
example response
{ "version": "f41822f", "deployed_at": "..." }
try it: curl -s "https://real-signal.ai/api/version"
GET /api/health
Simple liveness probe.
example response
{ "ok": true }
try it: curl -s "https://real-signal.ai/api/health"
POST /api/mcp
params: JSON-RPC 2.0 body — methods: initialize, tools/list, tools/call, ping
The MCP server — 21 tools over the pocket cognition layer (atmosphere, moment quality, legitimacy index, silence + counterfactual ledgers, predictions accuracy, weekly/monthly citation reports, outlet autopilot simulator, benchmark). Read-only except the append-only benchmark submission. Every tools/call response carries the _meta attribution envelope. GET returns the discovery manifest; well-known copy at /.well-known/mcp.json.
example response
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "observed pockets: cluny." } ], "structuredContent": { "pockets": ["cluny"] }, "_meta": { "source": "real-signal.ai", "license": "CC BY-NC-ND 4.0", "attribution_required": true } } }
try it: curl -s "https://real-signal.ai/api/mcp?JSON-RPC 2.0 body — methods: initialize, tools/list, tools/call, ping"
GET /sitemap.xml
XML sitemap of every indexable surface — ~140 URLs (static + per-pocket + per-intent + per-outlet). lastmod per surface drives crawler revisits.
example response
<urlset xmlns="..."><url><loc>https://real-signal.ai/intent/cluny/quiet-now</loc><lastmod>2026-05-19</lastmod><changefreq>daily</changefreq><priority>0.6</priority></url>...</urlset>
try it: curl -s "https://real-signal.ai/sitemap.xml"