{"openapi":"3.1.0","info":{"title":"Commons Public API","version":"1.1.0","description":"Public REST API for Commons — campaign management, supporter CRM, and verified civic action. All endpoints require Bearer token authentication via API key (prefix ck_live_). Requests consume both a per-key and organization-global minute budget determined by plan."},"servers":[{"url":"/api/v1"}],"security":[{"bearerAuth":[]}],"paths":{"/":{"get":{"operationId":"getApiRoot","summary":"API root","description":"Returns API version and documentation link. No authentication required.","security":[],"responses":{"200":{"description":"API version info","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"version":{"type":"string","example":"v1"},"documentation":{"type":"string","example":"/api/v1/docs"}}}}}}}}}}},"/orgs":{"get":{"operationId":"getOrg","summary":"Get organization","description":"Returns the organization bound to the API key. Requires read scope.","responses":{"200":{"description":"Organization details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"description":"The compact organization API projection is unavailable"}}}},"/supporters":{"get":{"operationId":"listSupporters","summary":"List supporters","description":"List supporters with opaque database-cursor pagination and optional indexed filters. Filtered totals are omitted; follow cursor until hasMore is false for complete traversal. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"email","in":"query","schema":{"type":"string"},"description":"Filter by exact email (case-insensitive)"},{"name":"verified","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filter by verification status"},{"name":"email_status","in":"query","schema":{"type":"string","enum":["subscribed","unsubscribed","bounced","complained"]},"description":"Filter by email subscription status"},{"name":"source","in":"query","schema":{"type":"string","enum":["csv","action_network","everyaction","nationbuilder","mailchimp","salsa","mobilize","actblue","engaging_networks","civicrm","salesforce","organic","widget"]},"description":"Filter by import source"},{"name":"tag","in":"query","schema":{"type":"string"},"description":"Filter by tag ID"}],"responses":{"200":{"description":"Paginated list of supporters","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Supporter"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createSupporter","summary":"Create supporter","description":"Create a new supporter. Requires write scope. Duplicate emails return 409.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSupporterInput"}}}},"responses":{"201":{"description":"Supporter created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Supporter"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/supporters/{id}":{"get":{"operationId":"getSupporter","summary":"Get supporter","description":"Get a single supporter by ID. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Supporter details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Supporter"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateSupporter","summary":"Update supporter","description":"Update supporter fields. Requires write scope. At least one field must be provided.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSupporterInput"}}}},"responses":{"200":{"description":"Supporter updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteSupporter","summary":"Delete supporter","description":"Permanently delete a supporter. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Supporter deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/campaigns":{"get":{"operationId":"listCampaigns","summary":"List campaigns","description":"List campaigns with cursor pagination and optional filters. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"status","in":"query","schema":{"type":"string","enum":["DRAFT","ACTIVE","PAUSED","COMPLETE"]},"description":"Filter by campaign status"},{"name":"type","in":"query","schema":{"type":"string","enum":["LETTER","EVENT","FORM"]},"description":"Filter by campaign type"}],"responses":{"200":{"description":"Paginated list of campaigns","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createCampaign","summary":"Create campaign","description":"Create a new campaign in DRAFT status. Requires write scope.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignInput"}}}},"responses":{"201":{"description":"Campaign created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CampaignDetail"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/campaigns/{id}":{"get":{"operationId":"getCampaign","summary":"Get campaign","description":"Get a single campaign by ID. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Campaign details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CampaignFull"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateCampaign","summary":"Update campaign","description":"Update campaign fields. Requires write scope. At least one field must be provided.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignInput"}}}},"responses":{"200":{"description":"Campaign updated","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/campaigns/{id}/actions":{"get":{"operationId":"listCampaignActions","summary":"List campaign actions","description":"List actions taken on a campaign with cursor pagination. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"},{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"verified","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filter by verification status"}],"responses":{"200":{"description":"Paginated list of campaign actions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CampaignAction"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/tags":{"get":{"operationId":"listTags","summary":"List tags","description":"List tags using an opaque database cursor. Exact supporter counts come from the tag projection; a complete traversal must follow the cursor until hasMore is false. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"description":"List of tags","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createTag","summary":"Create tag","description":"Create a new tag. Requires write scope. Duplicate names return 409.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Tag name"}}}}}},"responses":{"201":{"description":"Tag created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/tags/{id}":{"patch":{"operationId":"updateTag","summary":"Rename tag","description":"Rename a tag. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"New tag name"}}}}}},"responses":{"200":{"description":"Tag renamed","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteTag","summary":"Delete tag","description":"Permanently delete a tag. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Tag deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/usage":{"get":{"operationId":"getUsage","summary":"Get billing usage","description":"Returns current billing period usage for the organization. Requires read scope.","responses":{"200":{"description":"Usage data","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Usage"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/keys":{"post":{"operationId":"createApiKey","summary":"Create API key","description":"Create a new API key. Requires session authentication (org owner or editor role), not Bearer token auth. The full key is returned only once in the response.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyInput"}}}},"responses":{"201":{"description":"API key created (key shown once)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ApiKeyCreated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/keys/{id}":{"patch":{"operationId":"renameApiKey","summary":"Rename API key","description":"Rename an API key. Requires session authentication (org owner or editor role). Pass orgSlug as query parameter.","security":[],"parameters":[{"$ref":"#/components/parameters/resourceId"},{"name":"orgSlug","in":"query","required":true,"schema":{"type":"string"},"description":"Organization slug"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"New key name"}}}}}},"responses":{"200":{"description":"Key renamed","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"revokeApiKey","summary":"Revoke API key","description":"Revoke (soft-delete) an API key. Requires session authentication (org owner or editor role). Pass orgSlug as query parameter.","security":[],"parameters":[{"$ref":"#/components/parameters/resourceId"},{"name":"orgSlug","in":"query","required":true,"schema":{"type":"string"},"description":"Organization slug"}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"revoked":{"type":"boolean","example":true}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/events":{"get":{"operationId":"listEvents","summary":"List events","description":"List events with cursor pagination and optional filters. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"status","in":"query","schema":{"type":"string","enum":["DRAFT","PUBLISHED","CANCELLED","COMPLETED"]},"description":"Filter by event status"},{"name":"eventType","in":"query","schema":{"type":"string","enum":["IN_PERSON","VIRTUAL","HYBRID"]},"description":"Filter by event type"}],"responses":{"200":{"description":"Paginated list of events","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/events/{id}":{"get":{"operationId":"getEvent","summary":"Get event","description":"Get a single event by ID. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Event details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EventDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/donations":{"get":{"operationId":"listDonations","summary":"List donations","description":"List donations with cursor pagination and optional filters. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","completed","refunded"]},"description":"Filter by donation status"},{"name":"campaignId","in":"query","schema":{"type":"string"},"description":"Filter by campaign ID"}],"responses":{"200":{"description":"Paginated list of donations","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Donation"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/donations/{id}":{"get":{"operationId":"getDonation","summary":"Get donation","description":"Get a single donation by ID. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Donation details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DonationDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/workflows":{"get":{"operationId":"listWorkflows","summary":"List workflows","description":"List automation workflows with cursor pagination and optional filters. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"enabled","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filter by enabled status"}],"responses":{"200":{"description":"Paginated list of workflows","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Workflow"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/workflows/{id}":{"get":{"operationId":"getWorkflow","summary":"Get workflow","description":"Get a single workflow by ID including step definitions. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Workflow details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WorkflowDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/sms":{"get":{"operationId":"listSmsBlasts","summary":"List SMS blasts","description":"List SMS blasts with cursor pagination and optional filters. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","sending","sent","failed"]},"description":"Filter by blast status"}],"responses":{"200":{"description":"Paginated list of SMS blasts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SmsBlast"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/calls":{"get":{"operationId":"listCalls","summary":"List patch-through calls","description":"List patch-through calls with cursor pagination and optional filters. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"status","in":"query","schema":{"type":"string","enum":["initiated","ringing","in-progress","completed","failed","no-answer","busy"]},"description":"Filter by call status"},{"name":"campaignId","in":"query","schema":{"type":"string"},"description":"Filter by campaign ID"}],"responses":{"200":{"description":"Paginated list of patch-through calls","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PatchThroughCall"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/representatives":{"get":{"operationId":"listRepresentatives","summary":"List representatives","description":"List international representatives for one required country from a single byte-bounded database page. Constituency lookup remains unavailable until a compact constituency projection exists. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"country","in":"query","required":true,"schema":{"type":"string"},"description":"Country scope"}],"responses":{"200":{"description":"Paginated list of representatives","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Representative"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"503":{"description":"Constituency lookup is unavailable pending a compact projection"}}}},"/activity":{"get":{"operationId":"listDecisionMakerActivity","summary":"List scoped decision-maker activity","description":"Returns one bounded indexed page for one followed decision-maker and one activity source. vote/sponsor pages may be sparse; follow the opaque cursor until hasMore is false. Receipt activity is served only from the compact accountability projection. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"},{"name":"decision_maker_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"activity_type","in":"query","required":true,"schema":{"type":"string","enum":["vote","sponsor","receipt"]}}],"responses":{"200":{"description":"Paginated activity from one compact source","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/resolve-address":{"post":{"operationId":"resolveAddress","summary":"Resolve a US street address to district + officials","description":"Resolve a street address to its district, officials, and two independent freshness clocks (boundary geometry vs. officials sync). Requires read scope and a Bearer ck_live_ key. POST is metered and rate-capped per plan; inactive/no-plan keys receive a finite free-trial quota, not recurring free volume. Retries WITHOUT an Idempotency-Key re-bill under a fresh requestId; resupplying the same key WITH THE SAME address payload bills once (the key is bound to the payload — the same key with a different address is a distinct billable request, not an error). Returns the congressional district (`district`, unchanged) plus `districts`, an array of every boundary type the atlas serves at that address (state legislative, county, city, school, township, tribal — see `coverage.boundaryTypes` for the honest per-type coverage class). Officials rosters exist for congressional districts only (`coverage.officialsTypes`); other entries carry boundary identity without officials. Billing is per resolution call, never per district type returned.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{8,64}$"},"description":"Optional client idempotency key (8-64 chars of [A-Za-z0-9_.:-]), namespaced to your org AND bound to the request payload. A retry with the SAME key and SAME address re-executes the resolve but bills exactly once; the same key with a DIFFERENT address is treated as a new billable request (not rejected). The effective ledger requestId is echoed in meta.requestId."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveAddressInput"}}}},"responses":{"200":{"description":"Resolved address. district may be null when the address is outside coverage — an honest empty result, not an error.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResolveAddressResult"},"meta":{"type":"object","properties":{"requestId":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Address could not be geocoded (GEOCODE_MISS)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"GEOCODE_MISS","message":"Address not found"}}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"502":{"description":"Upstream/infrastructure failure — typed, never billed. error.code is one of: ATLAS_UNAVAILABLE (atlas data source down), METERING_UNAVAILABLE (usage-ledger read failed; no resolve, no meter), METERING_WRITE_FAILED (resolution succeeded but the billable row never landed), AUTH_UNAVAILABLE (authentication backend outage), RATE_LIMITER_UNAVAILABLE (rate-limiter outage; no resolve, no meter), RESOLVE_FAILED (other resolver failure).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"ATLAS_UNAVAILABLE","message":"Atlas data source unavailable"}}}}}}}},"/networks":{"get":{"operationId":"listNetworks","summary":"List networks","description":"List coalition networks the authenticated org belongs to. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"description":"Paginated list of networks","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Network"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/networks/{id}":{"get":{"operationId":"getNetwork","summary":"Get network detail","description":"Returns bounded network metadata. The complete member roster is intentionally omitted; memberCount is exposed only when the compact coalition projection is exact. Requires the org to be an active member and read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Network detail without roster expansion","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NetworkDetail"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/networks/{id}/stats":{"get":{"operationId":"getNetworkStats","summary":"Get network stats","description":"Returns aggregate statistics across all active member orgs in the network. Requires the org to be an active member. Requires read scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Network aggregate statistics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/NetworkStats"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhooks":{"get":{"operationId":"listWebhooks","summary":"List webhook subscriptions","description":"Returns one opaque database-cursor page of webhook subscriptions. Requires read scope.","parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"description":"Array of webhook subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createWebhook","summary":"Create webhook subscription","description":"Subscribes an HTTPS endpoint to one or more org events. Returns the signing secret ONCE — store it now; Commons will never display it again. Requires write scope.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookInput"}}}},"responses":{"201":{"description":"Webhook created (with one-time signingSecret)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookCreated"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Webhook destination policy is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/webhooks/{id}":{"get":{"operationId":"getWebhook","summary":"Get webhook subscription","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Webhook subscription","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Webhook"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateWebhook","summary":"Update webhook subscription","description":"Update URL, events, enabled state, or description. Re-enabling resets the failureCount. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookInput"}}}},"responses":{"200":{"description":"Updated webhook subscription","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Webhook"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteWebhook","summary":"Delete webhook subscription","description":"Removes the subscription atomically and drains delivery history asynchronously in bounded pages. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"Webhook deleted","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhooks/{id}/rotate-secret":{"post":{"operationId":"rotateWebhookSecret","summary":"Rotate webhook signing secret","description":"Issues a new signing secret. The previous secret continues to verify within the rotation window so receivers can roll over without dropped deliveries. The new secret is returned ONCE. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"200":{"description":"New signing secret (returned once)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookSecretRotated"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhooks/{id}/test-fire":{"post":{"operationId":"testWebhookDelivery","summary":"Queue a signed test delivery","description":"Queues a targeted webhook.test POST to one enabled endpoint. This proves only Commons sender-side dispatch; inspect delivery history for receiver status. Requires write scope.","parameters":[{"$ref":"#/components/parameters/resourceId"}],"responses":{"202":{"description":"Test delivery queued","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookTestDelivery"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Webhook is disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key with ck_live_ prefix"}},"parameters":{"resourceId":{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Resource ID"},"cursor":{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque database cursor returned by the previous page"},"limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":50},"description":"Number of items per page (max 50)"}},"schemas":{"PaginationMeta":{"type":"object","properties":{"cursor":{"type":["string","null"],"description":"Cursor for next page, or null if no more pages"},"hasMore":{"type":"boolean"},"total":{"type":"integer","description":"Total number of matching records"},"truncated":{"type":"boolean","description":"True when a bounded scan capped the result and `total` reflects only the scanned window rather than the complete set. Page with `cursor` to walk the in-window records."},"scanLimit":{"type":"integer","description":"Maximum records scanned to produce this page when `truncated` is present."}}},"Supporter":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"},"name":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"country":{"type":["string","null"]},"phone":{"type":["string","null"]},"verified":{"type":"boolean"},"emailStatus":{"type":"string"},"source":{"type":"string"},"customFields":{"type":["object","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}}}},"CreateSupporterInput":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Supporter email (must contain @)"},"name":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string","default":"US"},"phone":{"type":"string"},"source":{"type":"string","description":"Import source identifier"},"customFields":{"type":"object","description":"Arbitrary key-value metadata"},"tags":{"type":"array","items":{"type":"string"},"description":"Array of tag IDs to attach"}}},"UpdateSupporterInput":{"type":"object","properties":{"name":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"phone":{"type":"string"},"customFields":{"type":"object"}},"description":"At least one field must be provided."},"Campaign":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["LETTER","EVENT","FORM"]},"title":{"type":"string"},"body":{"type":["string","null"]},"status":{"type":"string","enum":["DRAFT","ACTIVE","PAUSED","COMPLETE"]},"templateId":{"type":["string","null"]},"debateEnabled":{"type":"boolean"},"debateThreshold":{"type":["integer","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"counts":{"type":"object","properties":{"actions":{"type":"integer"},"deliveries":{"type":"integer"}}}}},"CampaignDetail":{"type":"object","description":"Campaign as returned from POST (no counts)","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["LETTER","EVENT","FORM"]},"title":{"type":"string"},"body":{"type":["string","null"]},"status":{"type":"string","enum":["DRAFT","ACTIVE","PAUSED","COMPLETE"]},"templateId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CampaignFull":{"type":"object","description":"Campaign detail with targets field","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["LETTER","EVENT","FORM"]},"title":{"type":"string"},"body":{"type":["string","null"]},"status":{"type":"string","enum":["DRAFT","ACTIVE","PAUSED","COMPLETE"]},"targets":{"type":["object","null"],"description":"Campaign target configuration"},"templateId":{"type":["string","null"]},"debateEnabled":{"type":"boolean"},"debateThreshold":{"type":["integer","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"counts":{"type":"object","properties":{"actions":{"type":"integer"},"deliveries":{"type":"integer"}}}}},"CreateCampaignInput":{"type":"object","required":["title","type"],"properties":{"title":{"type":"string","description":"Campaign title (non-empty)"},"type":{"type":"string","enum":["LETTER","EVENT","FORM"]},"body":{"type":"string","description":"Campaign body text"},"templateId":{"type":"string","description":"ID of template to use (must belong to org)"}}},"UpdateCampaignInput":{"type":"object","properties":{"title":{"type":"string"},"body":{"type":"string"},"status":{"type":"string","enum":["DRAFT","ACTIVE","PAUSED","COMPLETE"]}},"description":"At least one field must be provided."},"CampaignAction":{"type":"object","properties":{"id":{"type":"string"},"campaignId":{"type":"string"},"supporterId":{"type":["string","null"]},"verified":{"type":"boolean"},"engagementTier":{"type":"integer"},"districtHash":{"type":["string","null"]},"sentAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"Tag":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"supporterCount":{"type":"integer"}}},"Usage":{"type":"object","properties":{"verifiedActions":{"type":"integer"},"maxVerifiedActions":{"type":"integer"},"emailsSent":{"type":"integer"},"maxEmails":{"type":"integer"}}},"OrgResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"avatar":{"type":["string","null"]},"createdAt":{"type":"null"},"counts":{"type":"object","properties":{"supporters":{"type":["integer","null"]},"campaigns":{"type":["integer","null"]},"templates":{"type":"null"}}},"countsExact":{"type":"object","properties":{"supporters":{"type":"boolean"},"campaigns":{"type":"boolean"},"templates":{"type":"boolean","enum":[false]}}}}}}},"CreateApiKeyInput":{"type":"object","required":["orgSlug"],"properties":{"orgSlug":{"type":"string","description":"Organization slug"},"name":{"type":"string","default":"Default","description":"Display name for the key"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write"]},"default":["read"],"description":"Permission scopes (write implies read)"}}},"ApiKeyCreated":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string","description":"Full API key — shown only once"},"prefix":{"type":"string","description":"Key prefix for identification (e.g. ck_live_abc...)"},"name":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"}}},"Event":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"eventType":{"type":"string","enum":["IN_PERSON","VIRTUAL","HYBRID"]},"startAt":{"type":"string","format":"date-time"},"endAt":{"type":["string","null"],"format":"date-time"},"timezone":{"type":["string","null"]},"venue":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"virtualUrl":{"type":["string","null"]},"capacity":{"type":["integer","null"]},"status":{"type":"string","enum":["DRAFT","PUBLISHED","CANCELLED","COMPLETED"]},"rsvpCount":{"type":"integer"},"attendeeCount":{"type":"integer"},"verifiedAttendees":{"type":"integer"},"campaignId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"EventDetail":{"type":"object","description":"Full event detail including address and configuration fields","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"eventType":{"type":"string","enum":["IN_PERSON","VIRTUAL","HYBRID"]},"startAt":{"type":"string","format":"date-time"},"endAt":{"type":["string","null"],"format":"date-time"},"timezone":{"type":["string","null"]},"venue":{"type":["string","null"]},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"virtualUrl":{"type":["string","null"]},"capacity":{"type":["integer","null"]},"waitlistEnabled":{"type":"boolean"},"requireVerification":{"type":"boolean"},"status":{"type":"string","enum":["DRAFT","PUBLISHED","CANCELLED","COMPLETED"]},"rsvpCount":{"type":"integer"},"attendeeCount":{"type":"integer"},"verifiedAttendees":{"type":"integer"},"campaignId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Donation":{"type":"object","properties":{"id":{"type":"string"},"campaignId":{"type":["string","null"]},"email":{"type":"string","format":"email"},"name":{"type":["string","null"]},"amountCents":{"type":"integer"},"currency":{"type":"string"},"recurring":{"type":"boolean"},"status":{"type":"string","enum":["pending","completed","refunded"]},"engagementTier":{"type":"integer"},"completedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"DonationDetail":{"type":"object","description":"Full donation detail including Stripe and district fields","properties":{"id":{"type":"string"},"campaignId":{"type":["string","null"]},"email":{"type":"string","format":"email"},"name":{"type":["string","null"]},"amountCents":{"type":"integer"},"currency":{"type":"string"},"recurring":{"type":"boolean"},"recurringInterval":{"type":["string","null"]},"status":{"type":"string","enum":["pending","completed","refunded"]},"engagementTier":{"type":"integer"},"districtHash":{"type":["string","null"]},"stripeSessionId":{"type":["string","null"]},"completedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"Workflow":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"trigger":{"type":"string"},"stepCount":{"type":"integer"},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"WorkflowDetail":{"type":"object","description":"Full workflow detail including step definitions","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"trigger":{"type":"string"},"steps":{"type":"array","items":{"type":"object"},"description":"Array of workflow step definitions"},"stepCount":{"type":"integer"},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"SmsBlast":{"type":"object","properties":{"id":{"type":"string"},"body":{"type":"string"},"fromNumber":{"type":"string"},"status":{"type":"string","enum":["draft","sending","sent","failed"]},"totalRecipients":{"type":"integer"},"sentCount":{"type":"integer"},"failedCount":{"type":"integer"},"campaignId":{"type":["string","null"]},"sentAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"PatchThroughCall":{"type":"object","properties":{"id":{"type":"string"},"callerPhone":{"type":"string"},"targetPhone":{"type":"string"},"targetName":{"type":["string","null"]},"status":{"type":"string","enum":["initiated","ringing","in-progress","completed","failed","no-answer","busy"]},"duration":{"type":["integer","null"]},"twilioCallSid":{"type":["string","null"]},"campaignId":{"type":["string","null"]},"districtHash":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Representative":{"type":"object","properties":{"id":{"type":"string"},"countryCode":{"type":"string"},"constituencyId":{"type":["string","null"]},"constituencyName":{"type":["string","null"]},"name":{"type":"string"},"party":{"type":["string","null"]},"chamber":{"type":["string","null"]},"office":{"type":["string","null"]},"phone":{"type":["string","null"]},"email":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"photoUrl":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Network":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active","suspended"]},"ownerOrgId":{"type":"string"},"memberCount":{"type":["integer","null"]},"memberCountExact":{"type":"boolean"},"role":{"type":"string","enum":["admin","member"]},"joinedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"NetworkDetail":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active","suspended"]},"ownerOrgId":{"type":"string"},"memberCount":{"type":["integer","null"]},"memberCountExact":{"type":"boolean"},"ownerOrg":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}}},"members":{"type":"null"},"membersAvailable":{"type":"boolean","enum":[false]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"NetworkStats":{"type":"object","properties":{"memberCount":{"type":"integer"},"totalSupporters":{"type":"integer"},"uniqueSupporters":{"type":"integer"},"verifiedSupporters":{"type":"integer"},"totalCampaignActions":{"type":"integer"},"verifiedCampaignActions":{"type":"integer"},"stateDistribution":{"type":"object","additionalProperties":{"type":"integer"},"description":"Geographic distribution by region code"}}},"WebhookEvent":{"type":"string","enum":["campaign_action.created","campaign.updated","supporter.created","supporter.updated","supporter.deleted","donation.completed","donation.refunded","event.rsvp_created"],"description":"Org-scoped event name. Payload schema is event-specific (JSON-encoded by sender)."},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}},"enabled":{"type":"boolean"},"description":{"type":["string","null"]},"createdAt":{"type":"integer","description":"Unix ms timestamp"},"lastDeliveredAt":{"type":["integer","null"],"description":"Unix ms timestamp of last successful delivery"},"failureCount":{"type":"integer","description":"Consecutive delivery failures since last success. Auto-disable at 5 dead deliveries."}}},"WebhookCreated":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","required":["signingSecret"],"properties":{"signingSecret":{"type":"string","description":"Signing secret used to verify deliveries via HMAC-SHA256(timestamp + \".\" + payload). Returned ONCE on creation — store it now. Cannot be retrieved later; rotate to generate a new one."}}}]},"WebhookSecretRotated":{"type":"object","required":["signingSecret"],"properties":{"signingSecret":{"type":"string","description":"New signing secret. The previous secret continues to verify within the rotation window."}}},"WebhookTestDelivery":{"type":"object","required":["deliveryId","event","queuedAt"],"properties":{"deliveryId":{"type":"string","description":"orgWebhookDeliveries row queued for this targeted test"},"event":{"type":"string","enum":["webhook.test"],"description":"Synthetic targeted diagnostic event; not a normal subscription event"},"queuedAt":{"type":"integer","description":"Unix ms timestamp"}}},"CreateWebhookInput":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"HTTPS endpoint to receive POST deliveries; maximum 2,048 UTF-8 bytes"},"events":{"type":"array","minItems":1,"maxItems":16,"items":{"$ref":"#/components/schemas/WebhookEvent"}},"description":{"type":"string","maxLength":512,"description":"Maximum 512 UTF-8 bytes"}}},"UpdateWebhookInput":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"Maximum 2,048 UTF-8 bytes"},"events":{"type":"array","minItems":1,"maxItems":16,"items":{"$ref":"#/components/schemas/WebhookEvent"}},"enabled":{"type":"boolean","description":"Re-enabling resets failureCount to 0."},"description":{"type":"string","maxLength":512,"description":"Maximum 512 UTF-8 bytes"}}},"ResolutionProvenance":{"type":"object","description":"Lineage of the resolved boundary/officials data. Mirrors the upstream resolver provenance by value. The emitted property set is exactly {source, tigerVintage} — no other fields are ever returned.","properties":{"source":{"type":"string","description":"Resolver/data source identifier"},"tigerVintage":{"type":"string","description":"Census TIGER boundary vintage used for the district match","example":"TIGER2024"}},"required":["source"]},"ResolveAddressInput":{"type":"object","required":["street","city","state","zip"],"properties":{"street":{"type":"string","description":"Street address line"},"city":{"type":"string"},"state":{"type":"string","description":"Two-letter state/province code","minLength":2,"maxLength":2},"zip":{"type":"string","description":"US ZIP (5 or 5+4 digits) only"},"country":{"type":"string","enum":["US","CA"],"description":"Optional country code; defaults to US. CA is rejected with 400 UNSUPPORTED_COUNTRY — only US addresses are resolvable."}}},"ResolveAddressResult":{"type":"object","properties":{"district":{"type":["object","null"],"description":"Resolved district object. null means the address is outside coverage — a valid result, NOT an error.","properties":{"id":{"type":"string","description":"District id, e.g. \"CA-12\""},"name":{"type":"string","description":"Human-readable district name"},"jurisdiction":{"type":"string"},"district_type":{"type":"string","enum":["congressional"],"description":"Always 'congressional' — this field is the congressional district. See districts[] for all boundary types."}}},"districts":{"type":"array","items":{"$ref":"#/components/schemas/ResolvedDistrict"},"description":"All boundary types served at this address, ordered by broadest federal first (congressional, then state legislative, county, city, school, township, tribal). Includes the congressional entry (same id as district) when present. Empty when outside coverage; may be non-empty with district null if only non-congressional types resolve. Only types listed in coverage.boundaryTypes can appear; absence of a listed type means either no such district exists at this address or the data is partial for that type — consult its coverage class. district_type is an open set: new types may be added, existing values are never renamed."},"coverage":{"$ref":"#/components/schemas/ResolveCoverage"},"provenance":{"$ref":"#/components/schemas/ResolutionProvenance"},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Match confidence; degraded results lower this rather than throwing"},"asOf":{"type":"object","description":"Two independent freshness clocks, kept as distinct keys and never collapsed into one.","properties":{"boundaryAsOf":{"type":["string","null"],"description":"Boundary-geometry vintage. null = degraded/unknown vintage (honest, never fabricated)."},"officialsAsOf":{"type":["string","null"],"description":"Officials-sync timestamp. null = degraded/unknown vintage (honest, never fabricated)."}}},"officials":{"type":"array","items":{"type":"object"},"description":"Officials for the resolved district (empty when outside coverage)"},"warning":{"type":["string","null"],"description":"Degraded-but-resolved guard. Its own field — never borrows either asOf clock."}}},"ResolvedDistrict":{"type":"object","required":["id","geoid","name","jurisdiction","district_type"],"properties":{"id":{"type":"string","description":"Stable district id. Congressional: display code (\"MN-08\"); other types: \"{type-alias}-{TIGER GEOID}\" (\"sldu-27011\")."},"geoid":{"type":"string","description":"Raw TIGER/Census GEOID (\"27011\", \"2711B\") — joinable against Census data products."},"name":{"type":"string"},"jurisdiction":{"type":"string","description":"Same value as district_type."},"district_type":{"type":"string","description":"Stable boundary-type identifier. Currently served: congressional, state-senate, state-house, county, city, unified-school, elementary-school, secondary-school, township, tribal. Open set — clients must tolerate new values."}}},"ResolveCoverage":{"type":"object","required":["boundaryTypes","officialsTypes"],"properties":{"boundaryTypes":{"type":"object","description":"Per-district-type coverage disclosure, keyed by district_type. A type ABSENT from this map is not served at all. \"national\": present wherever that district type exists in US governance. \"partial\": known regional/structural limits or build gaps — absence of that type in districts[] is not evidence no such district exists.","additionalProperties":{"type":"object","required":["coverage"],"properties":{"coverage":{"type":"string","enum":["national","partial"]},"note":{"type":"string","description":"Factual scope note (governance structure or known data gap)."}}}},"officialsTypes":{"type":"array","items":{"type":"string"},"description":"District types with officials rosters. Currently [\"congressional\"] — all other entries carry boundary identity without officials."}}},"ErrorEnvelope":{"type":"object","properties":{"data":{"type":"null"},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}}},"responses":{"BadRequest":{"description":"Bad request — invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"BAD_REQUEST","message":"Invalid JSON body"}}}}},"PaymentRequired":{"description":"Plan resolve quota exhausted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"RESOLVE_QUOTA_EXCEEDED","message":"Resolve quota exhausted for this plan period"}}}}},"TooManyRequests":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"RATE_LIMITED","message":"API rate limit exceeded"}}}}},"Unauthorized":{"description":"Authentication required or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"UNAUTHORIZED","message":"Missing or invalid Authorization header. Use: Bearer <api_key>"}}}}},"Forbidden":{"description":"API key lacks required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"FORBIDDEN","message":"API key does not have the 'write' scope"}}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"NOT_FOUND","message":"Resource not found"}}}}},"Conflict":{"description":"Resource already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"CONFLICT","message":"A resource with this identifier already exists"}}}}},"InternalError":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"data":null,"error":{"code":"INTERNAL_ERROR","message":"An unexpected error occurred"}}}}}}}}