Skip to content

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/me

Pagination

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/health

Response (200)

{
  "status": "ok",
  "version": "1.0.0"
}

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/me

Response (200)

{
  "organization_id": "00000000-0000-0000-0000-000000000001",
  "key_prefix": "sk_example_",
  "key_name": "Mein Integrations-Key"
}

Possible error statuses: 400, 401, 429

submissions

GET /submissions

List submissions

Cursor-paginated list of citizen submissions scoped to the API key’s municipality. Optional filtering by status and topic.

NameInRequiredDescription
cursorquerynostring
limitquerynointeger
statusquerynostring
topicquerynostring

Request

curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/submissions

Response (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

GET /submissions/{id}

Fetch a single submission

NameInRequiredDescription
idpathyesstringResource UUID

Request

curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/submissions/00000000-0000-0000-0000-000000000001

Response (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

sessions

GET /sessions

List committee sessions

Cursor-paginated list of council/committee sessions scoped to the API key’s municipality.

NameInRequiredDescription
cursorquerynostring
limitquerynointeger

Request

curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/sessions

Response (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

GET /sessions/{id}

Fetch a single session with submissions

NameInRequiredDescription
idpathyesstringResource UUID

Request

curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/sessions/00000000-0000-0000-0000-000000000001

Response (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

support

GET /support

List submission support counts

Cursor-paginated list of per-submission support tallies. Filter by submission ID to narrow down.

NameInRequiredDescription
cursorquerynostring
limitquerynointeger
submission_idquerynostring

Request

curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/support

Response (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

surveys

GET /surveys/{id}/results

Fetch survey results

Aggregated, anonymized survey results scoped to the API key’s municipality.

NameInRequiredDescription
idpathyesstringResource UUID

Request

curl -H "Authorization: Bearer sk_example_0000000000000000" https://api.decidio.de/api/v1/surveys/00000000-0000-0000-0000-000000000001/results

Response (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

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