{"components":{"parameters":{"dir":{"description":"Defaults to `desc` for date sorts, `asc` for text sorts.","in":"query","name":"dir","schema":{"enum":["asc","desc"],"type":"string"}},"from":{"description":"Window start, strict `YYYY-MM-DD`; defaults to four years before `to`.","example":"2022-08-31","in":"query","name":"from","schema":{"format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"}},"limit":{"in":"query","name":"limit","schema":{"default":100,"maximum":200,"minimum":1,"type":"integer"}},"location":{"description":"The location name, URL-encoded, treated as opaque data.","in":"path","name":"location","required":true,"schema":{"type":"string"}},"meetingQ":{"description":"Case-insensitive substring match over the meeting type, organization name and location.","in":"query","name":"q","schema":{"type":"string"}},"meetingSort":{"description":"Column to sort by; omitted keeps the endpoint's default order.","in":"query","name":"sort","schema":{"enum":["date","type","location"],"type":"string"}},"outcome":{"description":"Filter on the normalized outcome kind.","in":"query","name":"outcome","schema":{"enum":["passed","rejected","remitted","other"],"type":"string"}},"page":{"in":"query","name":"page","schema":{"default":1,"minimum":1,"type":"integer"}},"party":{"description":"The party label exactly as it appears in the protocols.","in":"path","name":"party","required":true,"schema":{"type":"string"}},"politicianId":{"in":"path","name":"id","required":true,"schema":{"format":"int64","type":"integer"}},"q":{"description":"Case-insensitive substring match on the title.","in":"query","name":"q","schema":{"type":"string"}},"sort":{"description":"Column to sort by; omitted keeps the endpoint's default order.","in":"query","name":"sort","schema":{"enum":["date","title"],"type":"string"}},"to":{"description":"Window end, strict `YYYY-MM-DD`; defaults to today (UTC).","example":"2026-08-31","in":"query","name":"to","schema":{"format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"}}},"responses":{"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Invalid parameter or body."},"NotFound":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The resource does not exist."},"Unavailable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The backing store is not configured."}},"schemas":{"AuditCategory":{"description":"The inconsistency taxonomy. `duplicate` means the meeting appears\nmore than once; `other` carries anything the list does not.\n","enum":["attendance","politician_identity","meeting_metadata","decision_content","decision_outcome","votes","missing_content","duplicate","other"],"type":"string"},"AuditIndicator":{"description":"One open report, redacted to what an indicator needs.","properties":{"category":{"$ref":"#/components/schemas/AuditCategory"},"created_at":{"format":"date-time","type":"string"},"decision_id":{"description":"Null when the whole meeting was flagged.","format":"int64","nullable":true,"type":"integer"},"id":{"format":"int64","type":"integer"},"status":{"$ref":"#/components/schemas/AuditStatus"}},"type":"object"},"AuditLogEntry":{"description":"One change-log row. The organization, meeting date and decision\nreference are stored on the row itself, so an entry stays\nreadable after a correction removed the meeting it described.\n","properties":{"category":{"$ref":"#/components/schemas/AuditCategory"},"created_at":{"format":"date-time","type":"string"},"decision_id":{"format":"int64","nullable":true,"type":"integer"},"decision_paragraph":{"type":"string"},"decision_title":{"type":"string"},"id":{"format":"int64","type":"integer"},"meeting_date":{"format":"date","type":"string"},"meeting_id":{"format":"int64","type":"integer"},"organization_name":{"type":"string"},"resolved_at":{"format":"date-time","type":"string"},"settled_at":{"format":"date-time","type":"string"},"source":{"description":"Who filed it — a reader, or an automated detector.","enum":["public","system"],"type":"string"},"status":{"$ref":"#/components/schemas/AuditStatus"}},"type":"object"},"AuditReport":{"additionalProperties":false,"properties":{"category":{"$ref":"#/components/schemas/AuditCategory"},"comment":{"description":"What is wrong, in your own words.","maxLength":5000,"type":"string"},"decision_id":{"description":"Omit or null to flag the whole meeting.","format":"int64","minimum":1,"nullable":true,"type":"integer"},"meeting_id":{"format":"int64","minimum":1,"type":"integer"},"name":{"description":"Your name. Required, unverified, never published — it is\ncontext for the person triaging the report.\n","maxLength":200,"type":"string"}},"required":["meeting_id","category","comment","name"],"type":"object"},"AuditStatus":{"description":"Where the report is: `pending` awaits triage, `accepted` has a\ncorrection in flight, `review` awaits a human's sign-off,\n`resolved` is done. Dismissed reports are never published.\n","enum":["pending","accepted","review","resolved"],"type":"string"},"BlocVote":{"properties":{"is_estimated":{"type":"boolean"},"party":{"type":"string"},"seat_count":{"type":"integer"},"vote":{"enum":[true,false,"abstain"],"type":"string"}},"type":"object"},"DecisionHit":{"properties":{"decision_id":{"format":"int64","type":"integer"},"meeting_date":{"format":"date","type":"string"},"meeting_id":{"format":"int64","type":"integer"},"organization_location":{"type":"string"},"organization_name":{"type":"string"},"paragraph_number":{"type":"string"},"title":{"type":"string"}},"type":"object"},"DecisionVotes":{"properties":{"blocs":{"items":{"$ref":"#/components/schemas/BlocVote"},"type":"array"},"individual":{"items":{"$ref":"#/components/schemas/VoteRecord"},"type":"array"},"summary":{"$ref":"#/components/schemas/VoteSummary"}},"type":"object"},"Error":{"properties":{"error":{"type":"string"}},"type":"object"},"LocationParties":{"properties":{"body_size":{"description":"People observed in the protocols — not mandates.","type":"integer"},"location":{"type":"string"},"parties":{"items":{"$ref":"#/components/schemas/PartyMembers"},"type":"array"}},"type":"object"},"LocationSummary":{"properties":{"latest_meeting_date":{"format":"date","type":"string"},"location":{"type":"string"},"meeting_count":{"type":"integer"}},"type":"object"},"MeetingDecision":{"properties":{"full_text":{"type":"string"},"id":{"format":"int64","type":"integer"},"ordinal":{"type":"integer"},"outcome":{"type":"string"},"outcome_kind":{"type":"string"},"paragraph_number":{"type":"string"},"reservations":{"items":{"$ref":"#/components/schemas/Reservation"},"type":"array"},"summary":{"type":"string"},"title":{"type":"string"},"votes":{"$ref":"#/components/schemas/DecisionVotes"},"voting_method":{"type":"string"}},"type":"object"},"MeetingGraph":{"properties":{"attendance":{"items":{"$ref":"#/components/schemas/Person"},"type":"array"},"correlation_id":{"description":"The row's pipeline slot identity (target-hash prefix + date-type tag).","type":"string"},"decisions":{"items":{"$ref":"#/components/schemas/MeetingDecision"},"type":"array"},"document_url":{"type":"string"},"id":{"format":"int64","type":"integer"},"meeting_date":{"format":"date","type":"string"},"meeting_type":{"type":"string"},"meeting_type_key":{"type":"string"},"organization_location":{"type":"string"},"organization_name":{"type":"string"}},"type":"object"},"MeetingListItem":{"properties":{"correlation_id":{"description":"The row's pipeline slot identity (target-hash prefix + date-type tag).","type":"string"},"decision_count":{"type":"integer"},"id":{"format":"int64","type":"integer"},"meeting_date":{"format":"date","type":"string"},"meeting_type":{"type":"string"},"meeting_type_key":{"type":"string"},"organization_location":{"type":"string"},"organization_name":{"type":"string"},"votering_count":{"type":"integer"}},"type":"object"},"MonthlyVotes":{"properties":{"abstain":{"type":"integer"},"did_not_vote":{"type":"integer"},"false":{"type":"integer"},"month":{"description":"YYYY-MM","type":"string"},"true":{"type":"integer"}},"type":"object"},"Pagination":{"properties":{"limit":{"type":"integer"},"page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}},"type":"object"},"PartyDetail":{"properties":{"body_size":{"type":"integer"},"location":{"type":"string"},"members":{"items":{"$ref":"#/components/schemas/Person"},"type":"array"},"monthly":{"items":{"$ref":"#/components/schemas/MonthlyVotes"},"type":"array"},"party":{"type":"string"},"recent_votings":{"items":{"$ref":"#/components/schemas/PartyVoting"},"type":"array"},"stats":{"$ref":"#/components/schemas/VoteSummary"}},"type":"object"},"PartyMembers":{"properties":{"members":{"type":"integer"},"party":{"type":"string"}},"type":"object"},"PartyVoting":{"properties":{"decision_id":{"format":"int64","type":"integer"},"meeting_date":{"format":"date","type":"string"},"meeting_id":{"format":"int64","type":"integer"},"outcome":{"type":"string"},"outcome_kind":{"type":"string"},"party_votes":{"$ref":"#/components/schemas/VoteSummary"},"title":{"type":"string"}},"type":"object"},"Person":{"description":"An attendee; politician_id is 0 when the name has no alias.","properties":{"name":{"type":"string"},"party":{"type":"string"},"politician_id":{"format":"int64","type":"integer"},"role":{"type":"string"}},"type":"object"},"PoliticianDecision":{"properties":{"decision_id":{"format":"int64","type":"integer"},"derived":{"type":"boolean"},"has_votering":{"description":"True when the decision had an individual roll-call — an empty individual_vote with has_votering true is the \"röstade ej\" bucket.","type":"boolean"},"individual_vote":{"enum":["",true,false,"abstain"],"type":"string"},"meeting_date":{"format":"date","type":"string"},"meeting_id":{"format":"int64","type":"integer"},"meeting_type":{"type":"string"},"meeting_type_key":{"type":"string"},"organization_name":{"type":"string"},"outcome":{"type":"string"},"outcome_kind":{"type":"string"},"paragraph_number":{"type":"string"},"source_url":{"type":"string"},"stance":{"enum":["agreed","disagreed","neutral"],"type":"string"},"stance_basis":{"type":"string"},"summary":{"type":"string"},"title":{"type":"string"}},"type":"object"},"PoliticianStats":{"properties":{"abstain":{"type":"integer"},"did_not_vote":{"type":"integer"},"false":{"type":"integer"},"location":{"type":"string"},"monthly":{"items":{"$ref":"#/components/schemas/MonthlyVotes"},"type":"array"},"name":{"type":"string"},"party":{"type":"string"},"politician_id":{"format":"int64","type":"integer"},"true":{"type":"integer"},"voteringar":{"type":"integer"}},"type":"object"},"PoliticianSummary":{"properties":{"id":{"format":"int64","type":"integer"},"location":{"type":"string"},"name":{"type":"string"},"party":{"type":"string"}},"type":"object"},"PopularDecision":{"properties":{"decision_id":{"format":"int64","type":"integer"},"meeting_date":{"format":"date","type":"string"},"meeting_id":{"format":"int64","type":"integer"},"meeting_type":{"type":"string"},"organization_location":{"type":"string"},"organization_name":{"type":"string"},"outcome":{"type":"string"},"outcome_kind":{"type":"string"},"paragraph_number":{"type":"string"},"title":{"type":"string"},"views":{"format":"int64","type":"integer"},"votes":{"allOf":[{"$ref":"#/components/schemas/VoteSummary"}],"description":"Null when the decision had no roll-call.","nullable":true}},"type":"object"},"Reservation":{"properties":{"politicians":{"items":{"$ref":"#/components/schemas/Person"},"type":"array"},"text":{"type":"string"}},"type":"object"},"Stats":{"properties":{"decisions":{"type":"integer"},"locations":{"type":"integer"},"meetings":{"type":"integer"},"politicians":{"type":"integer"}},"type":"object"},"VoteRecord":{"properties":{"name":{"type":"string"},"party":{"type":"string"},"politician_id":{"format":"int64","type":"integer"},"vote":{"enum":[true,false,"abstain"],"type":"string"}},"type":"object"},"VoteSummary":{"properties":{"abstain":{"type":"integer"},"did_not_vote":{"type":"integer"},"false":{"type":"integer"},"true":{"type":"integer"}},"type":"object"}}},"info":{"description":"The stable read surface behind sakfråga's frontend — and the contract\nfor anyone who wants to build their own. Every page of the bundled\nfrontend is a static HTML document that fills itself from these\nendpoints; nothing here is frontend-specific.\n\nConventions:\n\n* The API is read-only with one exception: `POST /api/v1/audits`\n  accepts an inconsistency report about a meeting or decision.\n  Decision views are counted server-side from decision-page requests\n  — no telemetry endpoint exists and nothing about the reader is\n  stored.\n* Audit reports are public information, but their free text and their\n  submitter are not: every audit response carries the target, the\n  category, the status and the display context, and never the\n  comment, the submitter's name or their address.\n* All responses are JSON. Errors are `{\"error\": \"message\"}` with a\n  4xx/5xx status.\n* Every date is a strict `YYYY-MM-DD` string, in parameters and\n  responses alike; `from`/`to` windows default to the last four\n  years and may span at most ten.\n* Collections are never `null` — an empty result is `[]`.\n* `outcome_kind` is a normalized vocabulary (`passed`, `rejected`,\n  `remitted`, `other`, or `\"\"` when unknown) derived from the raw\n  Swedish `outcome` text via a configured lexicon. The raw text is\n  always included alongside.\n* Vote buckets are `yes`, `no`, `abstain` and `did_not_vote` — the\n  last one means a roll-call happened and the attendee cast no vote.\n* Paged collections share one query vocabulary: `page`, `limit`, `q`\n  (case-insensitive substring), `sort`, `dir` (`asc` | `desc`;\n  defaults to newest-first for dates, A–Ö for text) and answer with a\n  `pagination` object. The filter and sort columns fit each data\n  type: decision tables match `q` on the title and add `outcome`;\n  meeting lists match `q` on type, organization and location.\n","title":"Sakfråga public API","version":"1"},"openapi":"3.0.3","paths":{"/api/v1/activity":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"active":{"items":{"properties":{"date":{"format":"date","type":"string"},"stages":{"additionalProperties":{"type":"integer"},"type":"object"}},"type":"object"},"type":"array"}},"type":"object"}}},"description":"Dates currently being processed, with pipeline stages."}},"summary":"Live scanner activity by meeting date","tags":["discovery"]}},"/api/v1/audits":{"get":{"description":"Every audit request that has not been dismissed, newest first —\nwhat was reported, on which meeting or decision, and how far it\ngot. A `resolved` row reads as \"amended after review\".\n\nDismissed reports never appear: dismissal is moderation, and\nshowing them would reward spam-to-be-seen.\n","parameters":[{"in":"query","name":"limit","schema":{"default":50,"maximum":200,"minimum":1,"type":"integer"}},{"in":"query","name":"offset","schema":{"default":0,"minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AuditLogEntry"},"type":"array"},"total":{"description":"Unpaged total.","type":"integer"}},"type":"object"}}},"description":"One page of the change log."},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}},"summary":"The public change log","tags":["audits"]},"post":{"description":"Flag a whole meeting, or one decision within it, as inconsistent\nwith its source document. The report is stored and queued; it is\nnever acted on automatically.\n\nYour name is required and is moderation context only — it is not\nverified, and it is never shown publicly. The submitting address\nis recorded server-side for abuse control and is likewise never\npublished. Requests from a blocked address are refused.\n","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditReport"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"properties":{"id":{"format":"int64","type":"integer"},"status":{"enum":["pending"],"type":"string"}},"type":"object"}}},"description":"The report was queued."},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Submissions from this address are not accepted."},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/Unavailable"}},"summary":"Report an inconsistency","tags":["audits"]}},"/api/v1/decisions/popular":{"get":{"description":"Ranked by aggregate view count inside the window. Views are\ncounted server-side when the public decision page is requested —\nan aggregate per decision and day, nothing about the reader.\nEmpty until the counter has data.\n","parameters":[{"in":"query","name":"limit","schema":{"default":4,"maximum":10,"minimum":1,"type":"integer"}},{"description":"Days back to count views over.","in":"query","name":"window","schema":{"default":30,"maximum":365,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"decisions":{"items":{"$ref":"#/components/schemas/PopularDecision"},"type":"array"}},"type":"object"}}},"description":"The ranking, most viewed first."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Most read decisions","tags":["views"]}},"/api/v1/locations":{"get":{"parameters":[{"description":"Case-insensitive location prefix/substring.","in":"query","name":"q","schema":{"type":"string"}},{"description":"`meetings` ranks by activity instead of matching `q`.","in":"query","name":"sort","schema":{"enum":["meetings"],"type":"string"}},{"description":"Default 10 (typeahead) or 8 (`sort=meetings`).","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"locations":{"items":{"$ref":"#/components/schemas/LocationSummary"},"type":"array"}},"type":"object"}}},"description":"Matching locations."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Locations (typeahead and most-active list)","tags":["discovery"]}},"/api/v1/locations/{location}/meetings":{"get":{"parameters":[{"$ref":"#/components/parameters/location"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"},{"$ref":"#/components/parameters/meetingQ"},{"$ref":"#/components/parameters/meetingSort"},{"$ref":"#/components/parameters/dir"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"location":{"type":"string"},"meetings":{"items":{"$ref":"#/components/schemas/MeetingListItem"},"type":"array"},"pagination":{"$ref":"#/components/schemas/Pagination"}},"type":"object"}}},"description":"One page of the location's meetings, newest first."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Meetings held in one location (paged list)","tags":["meetings"]}},"/api/v1/locations/{location}/parties":{"get":{"parameters":[{"$ref":"#/components/parameters/location"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocationParties"}}},"description":"Members observed per party. `body_size` counts people seen in\nthe protocols — not mandates.\n"},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Party composition observed in one location","tags":["parties"]}},"/api/v1/locations/{location}/parties/{party}":{"get":{"parameters":[{"$ref":"#/components/parameters/location"},{"$ref":"#/components/parameters/party"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartyDetail"}}},"description":"The party detail. `recent_votings` is a fixed preview of the\nlatest 12 roll-calls — page the full list via `/votings`.\n"},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"One party's members, tallies and recent votings","tags":["parties"]}},"/api/v1/locations/{location}/parties/{party}/votings":{"get":{"description":"Every roll-call decision the party's members attended in the\nwindow, newest first, with the party's own vote tally per\ndecision. The paged/filtered/sorted table behind the party page.\n","parameters":[{"$ref":"#/components/parameters/location"},{"$ref":"#/components/parameters/party"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"},{"$ref":"#/components/parameters/q"},{"$ref":"#/components/parameters/outcome"},{"$ref":"#/components/parameters/sort"},{"$ref":"#/components/parameters/dir"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"location":{"type":"string"},"pagination":{"$ref":"#/components/schemas/Pagination"},"party":{"type":"string"},"votings":{"items":{"$ref":"#/components/schemas/PartyVoting"},"type":"array"}},"type":"object"}}},"description":"One page of the party's votings."},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"The party's full roll-call list (paged table)","tags":["parties"]}},"/api/v1/meetings":{"get":{"parameters":[{"description":"The day, strict `YYYY-MM-DD`.","example":"2026-03-12","in":"query","name":"date","required":true,"schema":{"format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$","type":"string"}},{"$ref":"#/components/parameters/meetingQ"},{"$ref":"#/components/parameters/meetingSort"},{"$ref":"#/components/parameters/dir"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"date":{"format":"date","type":"string"},"meetings":{"items":{"$ref":"#/components/schemas/MeetingListItem"},"type":"array"},"pagination":{"$ref":"#/components/schemas/Pagination"}},"type":"object"}}},"description":"One page of the date's meetings, ordered by location."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Meetings held on one date (paged list)","tags":["meetings"]}},"/api/v1/meetings/daily":{"get":{"parameters":[{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"days":{"items":{"properties":{"by_type":{"additionalProperties":{"type":"integer"},"type":"object"},"date":{"format":"date","type":"string"},"total":{"type":"integer"}},"type":"object"},"type":"array"},"from":{"format":"date","type":"string"},"to":{"format":"date","type":"string"}},"type":"object"}}},"description":"One entry per day with at least one meeting."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Meeting counts per day (heatmap)","tags":["discovery"]}},"/api/v1/meetings/recent":{"get":{"description":"A fixed preview for the frontpage, like `recent_votings` on the party detail — page the full history via the location and date endpoints.","parameters":[{"in":"query","name":"limit","schema":{"default":6,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"meetings":{"items":{"$ref":"#/components/schemas/MeetingListItem"},"type":"array"}},"type":"object"}}},"description":"Latest meetings, newest first."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Most recently held meetings","tags":["meetings"]}},"/api/v1/meetings/{id}":{"get":{"description":"The meeting with attendance and every decision, including\nindividual votes, bloc votes, vote summaries and reservations.\nThis is the one fetch behind the meeting and decision pages.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeetingGraph"}}},"description":"The meeting graph."},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"One meeting's full graph","tags":["meetings"]}},"/api/v1/meetings/{id}/audits":{"get":{"description":"The reports still in flight (`pending`, `accepted` or `review`)\nfor one meeting — what a client needs to mark the flagged detail\nas under review. A meeting with no open reports answers with an\nempty list rather than a 404.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"items":{"items":{"$ref":"#/components/schemas/AuditIndicator"},"type":"array"}},"type":"object"}}},"description":"The open reports, newest first."},"404":{"$ref":"#/components/responses/NotFound"},"503":{"$ref":"#/components/responses/Unavailable"}},"summary":"Open reports on one meeting","tags":["audits"]}},"/api/v1/politicians":{"get":{"parameters":[{"in":"query","name":"q","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"results":{"items":{"$ref":"#/components/schemas/PoliticianSummary"},"type":"array"}},"type":"object"}}},"description":"Up to 10 matches (empty array when `q` is empty)."}},"summary":"Politician name search","tags":["politicians"]}},"/api/v1/politicians/{id}/decisions":{"get":{"description":"Every decision from meetings the politician attended, with their\nrecorded vote where one exists and a derived stance otherwise.\nDrives the voting-record table: filterable, sortable and paged\nserver-side.\n","parameters":[{"$ref":"#/components/parameters/politicianId"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"},{"description":"Restrict to one meeting_type_key.","in":"query","name":"meeting_type","schema":{"type":"string"}},{"description":"`true` keeps only explicit evidence (own vote, reservation, proposal); `false` keeps only derived stances.","in":"query","name":"explicit","schema":{"type":"boolean"}},{"in":"query","name":"stance","schema":{"enum":["agreed","disagreed","neutral"],"type":"string"}},{"description":"What the politician voted. `did_not_vote` matches decisions where a roll-call happened without them; decisions that never had a roll-call match no vote bucket.","in":"query","name":"vote","schema":{"enum":[true,false,"abstain","did_not_vote"],"type":"string"}},{"$ref":"#/components/parameters/q"},{"$ref":"#/components/parameters/outcome"},{"$ref":"#/components/parameters/sort"},{"$ref":"#/components/parameters/dir"},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"decisions":{"items":{"$ref":"#/components/schemas/PoliticianDecision"},"type":"array"},"pagination":{"$ref":"#/components/schemas/Pagination"},"politician_id":{"format":"int64","type":"integer"}},"type":"object"}}},"description":"One page of the filtered, sorted record."},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"The politician's voting record (paged table)","tags":["politicians"]}},"/api/v1/politicians/{id}/meetings":{"get":{"parameters":[{"$ref":"#/components/parameters/politicianId"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"dates":{"items":{"format":"date","type":"string"},"type":"array"},"politician_id":{"format":"int64","type":"integer"},"politician_name":{"type":"string"}},"type":"object"}}},"description":"Attended meeting dates."},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"Dates of meetings the politician attended","tags":["politicians"]}},"/api/v1/politicians/{id}/stats":{"get":{"description":"Profile plus roll-call tallies and a monthly series. Deliberately\ncarries no attendance rate: no roster of expected attendees\nexists at municipality level, so a percentage would be invented.\n","parameters":[{"$ref":"#/components/parameters/politicianId"},{"$ref":"#/components/parameters/from"},{"$ref":"#/components/parameters/to"}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoliticianStats"}}},"description":"The stats; an unknown id answers zeroed values, not an error."},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"summary":"One politician's profile and vote tallies","tags":["politicians"]}},"/api/v1/search/decisions":{"get":{"description":"Case-insensitive substring match over decision titles, summaries and full text, newest first. Queries shorter than 3 characters answer an empty result set.\n","parameters":[{"in":"query","name":"q","required":true,"schema":{"minLength":3,"type":"string"}},{"in":"query","name":"limit","schema":{"default":7,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"results":{"items":{"$ref":"#/components/schemas/DecisionHit"},"type":"array"}},"type":"object"}}},"description":"Matching decisions (empty when `q` is too short)."},"400":{"$ref":"#/components/responses/BadRequest"}},"summary":"Full-text decision search","tags":["discovery"]}},"/api/v1/stats":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Stats"}}},"description":"Totals across the whole corpus."}},"summary":"Corpus-wide totals","tags":["discovery"]}}},"servers":[{"url":"/"}],"tags":[{"description":"Frontpage and location views — stats, heatmaps, search.","name":"discovery"},{"description":"Meetings and their full decision graphs.","name":"meetings"},{"description":"Politician search, profile and voting record.","name":"politicians"},{"description":"Per-location party composition and voting.","name":"parties"},{"description":"Most-read ranking, counted from decision-page reads.","name":"views"},{"description":"Reporting inconsistencies in the corpus, and the public record of\nwhat was reported and what came of it.\n","name":"audits"}]}