API reference
Complete reference for the public decidio REST API: authentication, pagination, rate limiting, endpoints and errors.
Authentication
Every authenticated request carries an API key as a Bearer token in the Authorization header. Keys are prefixed sk_, issued in the admin under "Integrations / API keys", scoped per municipality, and revocable at any time.
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/mePagination
Lists use cursor pagination. Pass ?cursor=<opaque> from the previous response envelope and optionally ?limit=<1..100> (default 20). The response is { data: [...], pagination: { next_cursor, has_more } }; follow next_cursor until has_more === false.
Rate limiting
Each API key is limited to 1,000 requests per hour. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining. When the limit is exceeded decidio returns 429 Too Many Requests with a Retry-After header (seconds until the window resets) and X-RateLimit-Reset (Unix timestamp of the reset).
Every response also carries the security headers X-Content-Type-Options: nosniff and Cache-Control: no-store; the Content-Type is always application/json; charset=utf-8. Do not cache responses on the client.
Endpoints
health
GET /health
Service health check
Returns the API status and version. Unauthenticated; safe for liveness probes and uptime monitors.
Request
curl https://api.decidio.de/api/v1/healthResponse (200)
{
"status": "ok",
"version": "1.0.0"
}Test environment — no real citizen data
Send a request to see a synthetic response.
me
GET /me
Inspect the authenticated API key
Returns the organization the API key is scoped to and the key’s descriptive metadata.
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/meResponse (200)
{
"organization_id": "00000000-0000-0000-0000-000000000001",
"key_prefix": "sk_example_",
"key_name": "Mein Integrations-Key"
}Possible error statuses: 400, 401, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
submissions
GET /submissions
List submissions
Cursor-paginated list of citizen submissions scoped to the API key’s municipality. Optional filtering by status and topic.
| Name | In | Required | Description |
|---|---|---|---|
| cursor | query | no | string |
| limit | query | no | integer |
| status | query | no | string |
| topic | query | no | string |
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/submissionsResponse (200)
{
"data": [
{
"id": "00000000-0000-0000-0000-000000000001",
"referenceNumber": null,
"description": "Example description (synthetic)",
"status": "eingegangen",
"topicCategoryName": null,
"priorityLevel": "normal",
"supportCount": 1,
"hasAttachments": false,
"protocolUrl": null,
"createdAt": "2026-01-01T12:00:00.000Z",
"statusChangedAt": "eingegangen"
}
],
"pagination": {
"next_cursor": null,
"has_more": false
}
}Possible error statuses: 400, 401, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
GET /submissions/{id}
Fetch a single submission
| Name | In | Required | Description |
|---|---|---|---|
| id | path | yes | string — Resource UUID |
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/submissions/00000000-0000-0000-0000-000000000001Response (200)
{
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"referenceNumber": null,
"description": "Example description (synthetic)",
"status": "eingegangen",
"topicCategoryName": null,
"priorityLevel": "normal",
"supportCount": 1,
"hasAttachments": false,
"protocolUrl": null,
"createdAt": "2026-01-01T12:00:00.000Z",
"statusChangedAt": "eingegangen"
}
}Possible error statuses: 400, 401, 404, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
sessions
GET /sessions
List committee sessions
Cursor-paginated list of council/committee sessions scoped to the API key’s municipality.
| Name | In | Required | Description |
|---|---|---|---|
| cursor | query | no | string |
| limit | query | no | integer |
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/sessionsResponse (200)
{
"data": [
{
"id": "00000000-0000-0000-0000-000000000001",
"committeeName": "Beispiel-Ausschuss",
"date": "2026-01-01",
"timeSlot": null,
"submissionCount": 1,
"createdAt": "2026-01-01T12:00:00.000Z"
}
],
"pagination": {
"next_cursor": null,
"has_more": false
}
}Possible error statuses: 400, 401, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
GET /sessions/{id}
Fetch a single session with submissions
| Name | In | Required | Description |
|---|---|---|---|
| id | path | yes | string — Resource UUID |
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/sessions/00000000-0000-0000-0000-000000000001Response (200)
{
"data": {
"id": "00000000-0000-0000-0000-000000000001",
"committeeName": "Beispiel-Ausschuss",
"date": "2026-01-01",
"timeSlot": null,
"submissionCount": 1,
"createdAt": "2026-01-01T12:00:00.000Z",
"submissions": [
{
"id": "00000000-0000-0000-0000-000000000001",
"referenceNumber": null,
"description": "Example description (synthetic)",
"status": "eingegangen",
"topicCategoryName": null,
"priorityLevel": "normal",
"supportCount": 1,
"hasAttachments": false,
"protocolUrl": null,
"createdAt": "2026-01-01T12:00:00.000Z",
"statusChangedAt": "eingegangen"
}
]
}
}Possible error statuses: 400, 401, 404, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
support
GET /support
List submission support counts
Cursor-paginated list of per-submission support tallies. Filter by submission ID to narrow down.
| Name | In | Required | Description |
|---|---|---|---|
| cursor | query | no | string |
| limit | query | no | integer |
| submission_id | query | no | string |
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/supportResponse (200)
{
"data": [
{
"submissionId": "example",
"referenceNumber": null,
"supportCount": 1,
"createdAt": "2026-01-01T12:00:00.000Z"
}
],
"pagination": {
"next_cursor": null,
"has_more": false
}
}Possible error statuses: 400, 401, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
surveys
GET /surveys/{id}/results
Fetch survey results
Aggregated, anonymized survey results scoped to the API key’s municipality.
| Name | In | Required | Description |
|---|---|---|---|
| id | path | yes | string — Resource UUID |
Request
curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/surveys/00000000-0000-0000-0000-000000000001/resultsResponse (200)
{
"data": {
"surveyId": "example",
"title": "Beispiel-Umfrage",
"status": "eingegangen",
"totalResponses": 1,
"questions": [
{
"questionText": "Beispielfrage?",
"questionType": "single_choice",
"options": [
{
"optionText": "Option A",
"responseCount": 1
}
]
}
]
}
}Possible error statuses: 400, 401, 404, 429
Test environment — no real citizen data
Send a request to see a synthetic response.
Errors
Errors follow a uniform envelope with error (human-readable) and code (machine identifier):
- 400 BAD_REQUEST — invalid query parameters or cursor.
- 401 UNAUTHORIZED — missing or invalid API key.
- 404 NOT_FOUND — resource does not exist or is not visible to this tenant.
- 429 RATE_LIMITED — rate window exhausted. Read Retry-After and retry after that many seconds.
{
"error": "Invalid API key",
"code": "UNAUTHORIZED"
}OpenAPI document
This reference is generated from a machine-readable OpenAPI 3.1 document. You can download it directly:
https://decidio.de/openapi.json