# MyPolitics for developers

Source-linked Arizona candidate research through one public contract.

## Start here

Public beta. No API key is required. Start with coverage, then discover candidate and topic IDs. The supported scope is AZ / 2026-general. Read [methodology](methodology.md) before presenting results as candidate statements or ballot information.

```sh
curl 'https://mypolitics.vote/api/v1/?resource=coverage'
curl 'https://mypolitics.vote/api/v1/?resource=candidates&state=AZ&limit=5'
curl 'https://mypolitics.vote/api/v1/?resource=topics&limit=5'
```

Every success includes `schema_version`, `dataset_version`, `snapshot_at`, `coverage`, `attribution`, and `data`. The source reference is often more limited than a verified position: preserve those limitations.

Schema 1.1.0 adds nullable `photo_url` to candidate records alongside `website`. These fields come from the same candidate directory as the app. A populated URL does not guarantee freshness or image reuse rights. Repository clients now accept both 1.0.0 and 1.1.0; update older clients that strictly require 1.0.0. Immutable 1.0.0 snapshots remain available with their original schema and content.

## API

[OpenAPI JSON](https://mypolitics.vote/openapi.json) | [Download public snapshot](https://mypolitics.vote/civic/dataset.json)

Use `GET /api/v1/?resource=NAME`:

| Resource | Parameters | Result |
| --- | --- | --- |
| coverage | state, election | Scope, gaps, snapshot age, record counts |
| candidates | q, office, district, limit, offset | Candidate summaries; q searches names, other filters are exact |
| candidate | id | One candidate and source references |
| topics | q, limit, offset | Topic IDs, names, and comparison statements |
| races | limit, offset | Present office/district groups and candidate IDs |
| evidence | id | Source URL, provenance, review status, citation URL |
| compare | ids, topic, limit, offset | Equal-topic source comparison; ids is 2 to 4 comma-separated IDs from one race |
| changes | since, limit, offset | Recorded observations after a numeric cursor |

All resources accept state/election scope and optional `version` for an existing immutable snapshot. Default page size is 20; maximum is 100. `next_offset: null` marks the last page. For changes, start at `since=0`, then use `next_cursor` until it equals `latest_cursor`; leave offset at zero while advancing the cursor.

JSON errors include a message and code. Statuses include 400 invalid input, 404 missing record, 405 unsupported method, 422 unsupported scope/incompatible comparison, 429 quota, and 503 unavailable dataset. Public requests currently share a node-local fixed-window quota of 120/minute per hashed network bucket. Network neighbors and proxy users can share a bucket; this is an abuse guard, not a purchased account quota. Respect `Retry-After` and `RateLimit-*` headers. Responses use ETag and short public cache headers. Do not send personal information.

## MCP

Remote endpoint: `https://mypolitics.vote/api/mcp.php` (also `/mcp`). Transport: Streamable HTTP, JSON responses, stateless sessions. Configure this URL using your client's remote-MCP settings. Client support and configuration vary.

Tools: `get_coverage`, `search_candidates`, `get_candidate`, `list_topics`, `list_races`, `compare_candidates`, `get_evidence`, `get_changes`. [Tool schemas](https://mypolitics.vote/civic-tools.json).

HTTP clients send both `application/json` and `text/event-stream` in Accept and negotiate the protocol with `initialize`. Supported versions: 2025-11-25, 2025-06-18, 2025-03-26. GET returns 405 because server-push streams are not offered. No user accounts, private quiz access, mutation tools, or arbitrary URL fetching are available. Browser origins are restricted to deployment-configured values; absent Origin is accepted for native clients.

## CLI and JavaScript client

The CLI is included in the repository at `packages/civic-tools`; it has not been published to npm. From a checkout:

```sh
node packages/civic-tools/cli.mjs coverage --json
node packages/civic-tools/cli.mjs candidates list --office Governor --json
node packages/civic-tools/cli.mjs topics --json
node packages/civic-tools/cli.mjs compare CANDIDATE_ID_1 CANDIDATE_ID_2 --topic TOPIC_ID --json
```

Replace placeholders with IDs returned by the directory. `--base-url http://127.0.0.1:8093` or `MYPOLITICS_BASE_URL` selects local preview. JSON goes to stdout; errors go to stderr. Exit 0 means success, 1 remote/runtime failure, and 2 invalid CLI usage.

```js
import { MyPoliticsClient } from './packages/civic-tools/client.mjs'
const civic = new MyPoliticsClient()
const result = await civic.candidates({ state: 'AZ', limit: 5 })
console.log(result.coverage, result.data.items)
```

TypeScript declarations are included. For stdio-only MCP clients, first run `npm ci --prefix packages/civic-tools`, then configure command `node` with arguments `[/absolute/path/to/packages/civic-tools/cli.mjs, mcp]`. Use actual absolute paths as separate strings. The bridge uses the official MCP SDK and proxies the same remote tools. It prints only protocol messages to stdout.

A dependency-free Python client is included at `packages/civic-tools/client.py`. Add that directory to your Python import path, then:

```python
from client import MyPoliticsClient
civic = MyPoliticsClient()
result = civic.candidates(state="AZ", limit=5)
print(result["coverage"], result["data"]["items"])
```

## Readable pages and attribution

[Candidate directory](https://mypolitics.vote/civic/) includes HTML, Markdown, and JSON profiles without executing JavaScript. [llms.txt](https://mypolitics.vote/llms.txt) and [sitemap](https://mypolitics.vote/sitemap.xml) provide navigation. These files help discovery but do not guarantee placement or citations by an AI service.

## Operating the dataset

From the repository, run `php scripts/export-civic.php` to read configured public database records into a new immutable snapshot. It makes no database writes. Then run `php scripts/build-civic-contract.php` and `node scripts/build-civic-public.mjs` to regenerate public artifacts. Review source coverage, test locally, and deploy together. The CLI-only export is not an HTTP endpoint. Historical files must remain available if referenced by integrations.

There is no automatic refresh job, billing system, registry listing, or uptime SLA in this beta. Freshness must be monitored and maintained by the operator.
