Developer

The SiLobbyist Data API

Programmatic access to bills, legislators, probability scores, money data, and session deadlines β€” built for big firms' internal systems. Plus webhooks that push legislative events into your stack.

v1 is in preview

The auth pattern and the /api/v1/status health endpoint are live today. The read endpoints below are the published design target for the pilot β€” shape your integration against this contract and we'll confirm field-level detail when your key is issued. Request API access β†’

Authentication

API keys, scoped per firm

Every integration gets its own key. Keys are tenant-scoped: a key can only ever address data in its own firm's namespace, and only lobbyist-approved, client-visible records. The private practice store (CRM, billing, drafts) is unreachable through the API by construction.

# Send the key with every request β€” either header works curl -H "Authorization: Bearer si_live_acme_9f2kQwErTyUiOpAsDf" \ https://silobbyist.com/api/v1/status # or curl -H "X-API-Key: si_live_acme_9f2kQwErTyUiOpAsDf" \ https://silobbyist.com/api/v1/status
Key formatMeaning
si_live_<tenant>_<secret>Production key β€” real data for your firm's tenant (<tenant> follows the portal slug rules: 3–30 chars, lowercase [a-z0-9-])
si_test_<tenant>_<secret>Sandbox key β€” same contract, fixture data, never touches production

Scopes

Keys carry least-privilege scopes: bills:read, legislators:read, probability:read, money:read, deadlines:read, webhooks:manage. Request only what you use.

Rotation

Rotate keys anytime from your tenant dashboard β€” old key stays valid for a 24-hour grace window so deploys don't race. Compromised key? Revoke it and it's dead in under a minute.

No shared keys

One key per integration, never one key per firm. CI, the CRM sync, and the client dashboard each get their own β€” so a leak is a single integration, not the firm.

Endpoint reference

What you can pull

All read endpoints below share one envelope, one pagination scheme, and one error format (see Conventions). Base URL: https://silobbyist.com/api/v1.

Bills Preview

MethodEndpointWhat it returns
GET/billsList bills. Filters: session (e.g. 2027-28), house, status, author, committee, topic, updated_since
GET/bills/{id}One bill: official status, location, last action, author, committees, your firm's tracked position if set. Every field links back to the leginfo record.
GET/bills/{id}/historyAppend-only action history β€” every status change we've seen, with observed-at timestamps. Nothing is ever rewritten.
GET/bills/{id}/votesCommittee and floor vote records (official tallies only β€” whip counts never leave the lobbyist's browser and are never in the API).

Legislators Preview

MethodEndpointWhat it returns
GET/legislators120 members. Filters: house, party, district, committee, term_out_year
GET/legislators/{id}District, party, leadership/committee roles, open-seat/term-limit status. Bios are public-record only β€” never invented.

Probability scores Preview

The Probability Index is the one score that travels with its full explanation. A score is never returned without its complete factor breakdown β€” never a black box.

MethodEndpointWhat it returns
GET/probability/{bill_id}Score (e.g. 62 Β± 8) plus all 18 factor signals, weights, the uncertainty band, the decision rule, and the honesty caveats. Estimates with stated assumptions β€” never predictions.
GET/probability/{bill_id}/runsScore history β€” every recomputation appended, old scores never rewritten.

Money data Preview

MethodEndpointWhat it returns
GET/money/contributionsCal-Access-derived giving. Filters: donor, recipient, cycle, min_amount. Every figure carries its filing ID + filing date.
GET/money/donors/{id}Donor profile: totals by cycle, recipients, overlap flags. Donor↔client overlap is a labeled name-match heuristic β€” reported as "verify before acting," never proof of coordination.

Deadlines Preview

MethodEndpointWhat it returns
GET/deadlinesUpcoming session deadlines (J.R. 61 dates) plus computed next deadlines for tracked bills. Filters: within_days, bill_id
GET/session-calendarThe official legislative calendar as structured data β€” the same source the site's timeline and Goldie read from.

Service Live

MethodEndpointWhat it returns
GET/statusAuth check + service metadata: version, your tenant, scopes, rate-limit policy, docs link. The reference implementation of the auth contract.

Example: list tracked-session bills

# Request GET /api/v1/bills?session=2027-28&status=committee&limit=2 Authorization: Bearer si_live_acme_9f2kQwErTyUiOpAsDf # Response 200 { "data": [ { "id": "AB-1234", "title": "Housing accountability: ministerial approvals", "house": "assembly", "status": "Assembly Housing β€” hearing set", "author": "Asm. Example", "last_action": "Referred to Com. on HOUSING", "last_action_date": "2027-01-14", "probability": { "score": 62, "band": 8, "breakdown_url": "/api/v1/probability/AB-1234" }, "next_deadline": { "label": "Last day for policy committees to hear bills", "date": "2027-04-30", "days_out": 12 }, "leginfo_url": "https://leginfo.legislature.ca.gov/…", "your_position": "support" } ], "meta": { "tenant": "acme", "as_of": "2027-01-15T08:00:00-08:00" }, "pagination": { "next_cursor": "eyJpZCI6IkFCLTEyMzUifQ==", "limit": 2 } }
What the API will never do

No private practice data (CRM contacts, billing, time entries, drafts) leaves the browser through this API. No whip counts β€” those never leave the lobbyist's browser, period. And the API is read-and-notify only: it can never send anything to a client on your behalf. The approval gate ("it drafts β€” you send") is enforced server-side, not just in the UI.

Conventions

One envelope, one versioning promise

ConventionRule
Response envelopeEvery 200 returns { data, meta: { tenant, as_of }, pagination? }. Errors return { ok: false, error: "code", message: "plain-language" }.
PaginationCursor-based: ?limit=50&cursor=…. Default 50, max 200. Cursors are opaque β€” don't construct them.
VersioningVersion is in the URL (/api/v1). v1 is stable once pilot keys ship: additive changes only, breaking changes get a new version with a 12-month deprecation notice and a migration guide.
TimestampsISO 8601 with offset. Dates are California legislative dates (America/Los_Angeles).
Errors400 bad request Β· 401 missing/invalid key Β· 403 valid key, out of scope Β· 404 unknown resource Β· 429 over quota (retry after Retry-After)

Rate limits

Quotas that grow with you

TierRequests / minuteBurstWebhooks
Sandbox (si_test_)3060Fixture events on demand
Pilot120240Up to 3 endpoints
Firm6001,200Up to 10 endpoints, signed + retried

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. A 429 includes Retry-After β€” honor it; hammering a 429 escalates to a temporary key suspension.

Webhooks

Legislative events, pushed to your stack

Subscribe to events and we POST signed JSON to your endpoint the moment they fire. Events are matched against your firm's tracked bills, issues, and deadlines β€” you only get what matters to you.

Event catalog

EventFires when
bill.status_changedA tracked bill moves β€” committee referral, hearing set, passed, amended, chaptered, vetoed
bill.amendedA new amended print appears on leginfo (re-check vote thresholds and your position letter's accuracy)
deadline.approachingA tracked bill's computed next deadline enters the watch window (≀10 days) or the alert window (≀3 days)
probability.score_shiftedA tracked bill's Probability Index score moves beyond its uncertainty band after a recomputation
filing.deadlineFPPC/lobbying filing deadlines (quarterly reports, registration renewals) enter the reminder window

Payload example

POST https://your-firm.example.com/hooks/silobbyist X-SiLobbyist-Signature: t=1727745600,v1=5f2c9a… Content-Type: application/json { "event": "bill.status_changed", "event_id": "evt_9f2kQwErTyUiOp", "tenant": "acme", "occurred_at": "2027-01-15T08:04:11-08:00", "data": { "bill_id": "AB-1234", "from": "Introduced", "to": "Assembly Housing β€” hearing set", "detail_url": "https://silobbyist.com/api/v1/bills/AB-1234" } }

Verifying signatures

Every delivery is signed with HMAC-SHA256 using your endpoint's secret. The signature header is t=<unix timestamp>,v1=<hex hmac>; the signed payload is <timestamp>.<raw body>. Reject anything older than 5 minutes.

import hmac, hashlib def verify(raw_body: bytes, header: str, secret: str) -> bool: parts = dict(p.split("=", 1) for p in header.split(",")) msg = parts["t"].encode() + b"." + raw_body expect = hmac.new(secret.encode(), msg, hashlib.sha256).hexdigest() return hmac.compare_digest(expect, parts["v1"])

Retry policy

RuleDetail
AttemptsUp to 8 deliveries per event over ~24 hours, exponential backoff (1m, 2m, 4m, 8m, 15m, 1h, 6h, 12h)
RetryableNetwork errors, timeouts (10s), 5xx responses
Not retried2xx (delivered), 4xx (your endpoint rejected it β€” fix the receiver)
Dead letterAfter the 8th failure the event lands in your tenant's dead-letter queue, visible in the dashboard for 30 days, with one-click replay
DedupeEvery event carries a stable event_id β€” process idempotently; replays reuse the same ID

Request access

Get a pilot key

Tell us about your integration and we'll issue sandbox keys first, then production. Include:

  • Your firm name and your SiLobbyist portal slug (e.g. silobbyist.com/acme)
  • What you're building (CRM sync, internal dashboard, client reporting)
  • Which endpoints and webhook events you need
  • Expected volume (requests/day)

Contact: [API-CONTACT-EMAIL]

⚠️ This contact is a placeholder β€” the real API contact address will be set before this page goes live. Pilot keys are issued manually during the preview period.