webhooks COMING
Push events when something you watch changes — so you don't have to poll the api. This page is the working reference of the real webhook surface, verified against the deployed functions code before a word was written. That surface is currently empty. Everything planned is marked DRAFT.
apps/poc-web/functions — _middleware.js, api/*, lib/*). The sprint-64 re-verification re-ran the full-tree search (webhook|hmac-sha|x-shinnslist-signature|delivery_attempt across apps/poc-web/functions/, packages/, scripts/): the only hit is the webhooks.html footer link in the scripts/gen-docs.mjs template — no events fire, no subscription api, no signing, no delivery jobs. The only unrelated sign-comment hits are signal-adapter copy (MLS subscribers, matched-record deliveries). We do not document endpoints that don't exist.the real surface: nothing ships LIVE
Verified against the deployed functions code — four honest negatives. This section is the only LIVE part of the page, because "nothing ships" is the verified truth:
| area | what the code does |
|---|---|
| events | nothing fires. No event is emitted for list purchases, list refreshes, credit events, or alert triggers — nothing in the codebase calls an outbound delivery. The api is poll-only today. |
| subscription management | no endpoint exists. There is no way to register a watch, a parcel watch list, or a callback url — no subscription api to call, no watch record stored. |
| signature verification | not implemented. No signing secret is issued, no signature header is sent, and no verification helper exists in the code. There is nothing to verify against. |
| retry behavior | no delivery jobs exist. No backoff schedule, no retry counts, no dead-letter handling — there is no delivery pipeline to describe. |
If you receive a shape not described anywhere on this page, it came from code that changed after 2026-09-29 — the verification date above is the freshness stamp.
planned: event catalog DRAFT
No events have shipped, so there is no catalog yet. Planned shape: one event per meaningful change on something you watch (a signal flips on a watched parcel, a list finishes a refresh, a credit event lands, an alert trigger fires). Event names are not final — the real catalog will be listed here, with exact names, the day they ship. Until then there are no event names to document, so none are printed here.
planned: payload envelope DRAFT
Planned: every delivery is an HTTPS POST with a JSON body carrying the event id, the event type, a timestamp, and the event data. Field names are not final — no example payload is printed here because any example would be invented. The exact envelope, with a real sample delivery, ships on this page at launch.
planned: subscription management DRAFT
Planned: subscribe a watch to a parcel (or a saved list) and register the HTTPS url we POST to, with per-endpoint control (pause, rotate the signing secret, delete). The management endpoints are not built yet — no subscription api exists to call today, and endpoint paths are not final. No curl examples are printed here because they would be fiction.
planned: signature verification DRAFT
Planned: every delivery is signed with HMAC over the raw request body using a per-endpoint signing secret, so you can prove the POST came from shinnslist and wasn't tampered with in flight. The exact header name, the secret-delivery flow, and the algorithm details are not final — no verification snippet is printed here because there is no code to verify against yet. When signing ships, this section carries the exact header name and a working verification example.
planned: retry + delivery policy DRAFT
Planned: retries with backoff on non-2xx responses from your receiver, then the delivery is marked failed and surfaced for inspection. Exact retry counts, the backoff schedule, delivery retention windows, and the failure-reporting surface are not final — the real policy is published here at launch, copied from the shipped code, not before.
planned: test endpoint DRAFT
Planned: a "send a test event" action on each registered endpoint, so you can verify your receiver handles a real signed delivery before anything watches a parcel. Not available yet — no test-event action exists to click or call today.
what's planned, not yet shipped DRAFT
The full planned surface, in one list. Every item here is not final — names, headers, paths, counts, and schedules will be verified against the shipped code before they replace these bullets:
- event catalog: parcel-watch events, list-refresh events, credit events, alert-trigger events — names TBD
- payload envelope: signed HTTPS POST, JSON body — field names TBD
- subscription management: watch registration, pause, secret rotation, delete — endpoints TBD
- signature verification: HMAC over raw body — header name + secret delivery TBD
- retry + delivery policy: backoff on non-2xx, failure surfacing — counts + schedule TBD
- test endpoint: send-a-test-event per registered url — not available
When the first event fires in production, the DRAFT badges on this page flip to LIVE and the bullets above become the verified reference.
what works today: poll the api LIVE
Until webhooks ship, poll the real endpoints. The getting started guide walks through your first parcel query; the api reference lists every live signal. A parcel-watch polling loop looks like this:
curl -s "https://shinnslist.com/api/intel?q=37.5407,-77.4360" \ -H "x-api-key: YOUR_KEY" | jq '.signals | keys'
Free tier gets 25 calls a day per key (intelPerDay: 25 in apps/poc-web/functions/lib/api-keys.js) — plenty for a watch list while push is on the roadmap.
the $0 alert channel: GET /api/health
For the "tell me when something breaks" use case, the codebase already ships a documented polling answer. The code's own comments (apps/poc-web/functions/lib/error-monitor.js) describe it this way: "When it crosses SPIKE_THRESHOLD, the /api/health readout flips errors.spike = true" and "poll /api/health (public, auth-exempt), so that IS the $0 alert channel."
GET /api/healthis public and auth-exempt — it sits inPUBLIC_PATHSinapps/poc-web/functions/_middleware.jsand is exempt from both rate limiting and the shared password gate. No key needed.- The response carries an
errorsobject fromgetErrorStats(), including aspikeboolean. It flipstruewhen ≥ 20 errors land in a trailing 10-minute window (SPIKE_THRESHOLD = 20,SPIKE_WINDOW_MS = 10 * 60_000). - Honest caveat, quoted from the same file: "counters are in-memory per isolate, so a spike is measured per isolate." The durable log trail (30-day TTL) only exists when the
SHINNSLIST_LOGSKV binding is wired; the newest 20 full entries (MAX_RECENT = 20) are kept in memory.
curl -s "https://shinnslist.com/api/health" | jq '.errors'
Response fields, re-derived from apps/poc-web/functions/api/health.js: ok, pipeline_version (v0.1.0), boundary_selftest (Richmond-VA-inside / Annapolis-MD-outside probe), d1 (binding state: ok/unbound/error), errors, ts.
Retry-After / retry_after_seconds contract documented on the rate limits page.next: docs hub · getting started · api reference · sdks