{
  "model_version": 1,
  "type": "api",
  "lang": "sv",
  "path": "/api",
  "alternates": {
    "html": "/api",
    "markdown": "/api.md",
    "json": "/api.json"
  },
  "title": "Öppna API:er och dataformat",
  "summary": "Så hämtar du Utlovats data med program: sidorna som JSON och Markdown, sök-API:et och det v1-kompatibla API:et.",
  "published_on": null,
  "updated_on": null,
  "authors": [],
  "status": null,
  "sections": [
    {
      "id": "oversikt",
      "heading": "Översikt",
      "blocks": [
        {
          "kind": "text",
          "text": "Utlovats data är öppna. Det finns tre sätt att hämta dem med ett API (programgränssnitt): varje sida som JSON (ett maskinläsbart format) och Markdown, en öppen söktjänst, och de v1-kompatibla adresserna under /api/v1. Ingen nyckel eller inloggning behövs."
        }
      ]
    },
    {
      "id": "sidformat",
      "heading": "Varje sida i tre format",
      "blocks": [
        {
          "kind": "text",
          "text": "Varje sida finns som HTML (webbsidan), Markdown och JSON. Lägg .md eller .json efter sidans adress; startsidan har /index.md och /index.json. JSON-formen är sidmodellen och följer schemat page-model. Fält som saknar värde är null."
        },
        {
          "kind": "table",
          "caption": "Sidtyper och adresser",
          "columns": [
            "Sidtyp",
            "Adressmönster",
            "Exempel"
          ],
          "rows": [
            [
              {
                "text": "Startsidan",
                "href": null,
                "date_on": null
              },
              {
                "text": "/ och /index.md, /index.json",
                "href": null,
                "date_on": null
              },
              {
                "text": "/",
                "href": "/",
                "date_on": null
              }
            ],
            [
              {
                "text": "Löfte",
                "href": null,
                "date_on": null
              },
              {
                "text": "/lofte/<id>",
                "href": null,
                "date_on": null
              },
              {
                "text": "/lofte/p-2026-0002",
                "href": "/lofte/p-2026-0002",
                "date_on": null
              }
            ],
            [
              {
                "text": "Parti",
                "href": null,
                "date_on": null
              },
              {
                "text": "/parti/<kod>",
                "href": null,
                "date_on": null
              },
              {
                "text": "/parti/c",
                "href": "/parti/c",
                "date_on": null
              }
            ],
            [
              {
                "text": "Riksdagsärende",
                "href": null,
                "date_on": null
              },
              {
                "text": "/arende/<id>",
                "href": null,
                "date_on": null
              },
              {
                "text": "/arende/m-1",
                "href": "/arende/m-1",
                "date_on": null
              }
            ],
            [
              {
                "text": "Ledamot",
                "href": null,
                "date_on": null
              },
              {
                "text": "/ledamot/<id>",
                "href": null,
                "date_on": null
              },
              {
                "text": "/ledamot",
                "href": "/ledamot",
                "date_on": null
              }
            ],
            [
              {
                "text": "Sakområde",
                "href": null,
                "date_on": null
              },
              {
                "text": "/sakomrade/<namn>",
                "href": null,
                "date_on": null
              },
              {
                "text": "/sakomrade/forsvar",
                "href": "/sakomrade/forsvar",
                "date_on": null
              }
            ],
            [
              {
                "text": "Rättelser",
                "href": null,
                "date_on": null
              },
              {
                "text": "/rattelser",
                "href": null,
                "date_on": null
              },
              {
                "text": "/rattelser",
                "href": "/rattelser",
                "date_on": null
              }
            ],
            [
              {
                "text": "Metod",
                "href": null,
                "date_on": null
              },
              {
                "text": "/metod",
                "href": null,
                "date_on": null
              },
              {
                "text": "/metod",
                "href": "/metod",
                "date_on": null
              }
            ],
            [
              {
                "text": "Öppna dataformat och API:er",
                "href": null,
                "date_on": null
              },
              {
                "text": "/api",
                "href": null,
                "date_on": null
              },
              {
                "text": "/api",
                "href": "/api",
                "date_on": null
              }
            ],
            [
              {
                "text": "Webbkarta",
                "href": null,
                "date_on": null
              },
              {
                "text": "/webbkarta",
                "href": null,
                "date_on": null
              },
              {
                "text": "/webbkarta",
                "href": "/webbkarta",
                "date_on": null
              }
            ],
            [
              {
                "text": "Sök",
                "href": null,
                "date_on": null
              },
              {
                "text": "/sok",
                "href": null,
                "date_on": null
              },
              {
                "text": "/sok",
                "href": "/sok",
                "date_on": null
              }
            ]
          ]
        },
        {
          "kind": "text",
          "text": "Sajtkartan för sökmotorer är /sitemap.xml."
        },
        {
          "kind": "text",
          "text": "Exempel med curl, som hämtar riktiga sidor:"
        },
        {
          "kind": "facts",
          "rows": [
            {
              "label": "Hämta som JSON",
              "text": "curl https://utlovat.se/lofte/p-2026-0002.json",
              "href": null,
              "date_on": null
            },
            {
              "label": "Hämta som Markdown",
              "text": "curl https://utlovat.se/lofte/p-2026-0002.md",
              "href": null,
              "date_on": null
            }
          ]
        }
      ]
    },
    {
      "id": "sok-api",
      "heading": "Sök-API",
      "blocks": [
        {
          "kind": "text",
          "text": "Sökningen är en egen öppen tjänst: GET /search?q=<ord> och samma under GET /api/v2/search. Parametrarna är q (frågan, exakt en gång), limit (antal träffar, 1 till 20, förval 10), type (vad som söks; i dag bara promise, löften), party (ett partis kortnamn), context (ett sammanhangs id, till exempel ett val) och cursor (markören för nästa sida). Varje parameter får anges högst en gång. Frågan får vara högst 200 tecken; högst åtta ord används och varje ord matchas som början av ett ord."
        },
        {
          "kind": "text",
          "text": "Svaret är JSON med ok, results, truncated och next_cursor. Varje träff har type, id, title, quote_excerpt, parties (högst åtta; parties_truncated säger om fler finns), status, page_url (sidan på sajten), source_url (källan som citatet kommer från) och last_changed_on (dagen då löftet senast ändrades). Bara publicerade löften finns med."
        },
        {
          "kind": "text",
          "text": "Fler träffar hämtas med next_cursor: skicka den som cursor med samma fråga och samma filter. Markören är opak; en ändrad markör eller en markör från en annan fråga ger felet 400. På sista sidan är next_cursor null. Ett svar har högst 20 träffar och högst 20 kB; truncated betyder att träffar fick vänta till nästa sida för att svaret skulle hålla storleken."
        },
        {
          "kind": "text",
          "text": "Ett felaktigt eller okänt värde ger felet 400 med en kod som säger vad som var fel, till exempel invalid_type (okänd typ), unsupported_type (typen går inte att söka efter än), unknown_party, unknown_context eller invalid_cursor."
        },
        {
          "kind": "text",
          "text": "Tjänsten svarar med CORS (regler för vilka webbplatser som får anropa den från en webbläsare) bara till sajtens egna adresser. Program utanför en webbläsare påverkas inte av CORS. För många anrop från samma klient ger 429 med rubriken Retry-After."
        },
        {
          "kind": "text",
          "text": "Exempel med curl:"
        },
        {
          "kind": "facts",
          "rows": [
            {
              "label": "Sök löften",
              "text": "curl \"https://search.utlovat.se/search?q=tillbaka&limit=5\"",
              "href": null,
              "date_on": null
            },
            {
              "label": "Samma sökning under /api/v2",
              "text": "curl \"https://search.utlovat.se/api/v2/search?q=tillbaka\"",
              "href": null,
              "date_on": null
            },
            {
              "label": "Bara ett partis löften",
              "text": "curl \"https://search.utlovat.se/api/v2/search?q=tillbaka&party=c&limit=5\"",
              "href": null,
              "date_on": null
            }
          ]
        }
      ]
    },
    {
      "id": "ledamot-api",
      "heading": "Ledamöternas alla rader",
      "blocks": [
        {
          "kind": "text",
          "text": "GET /api/v2/member/<id> på söktjänstens adress ger en ledamots alla röster och handlingar utan sidindelning. id är ledamotens id, samma som i /ledamot/<id>. Svaret är JSON med ok, member (id, name, page_url), votes, documents, counts och truncated."
        },
        {
          "kind": "text",
          "text": "Varje röst har id, decision_point_id, point_number, point_title, decided_on, matter_id, matter_title, matter_url, vote (yes, no, abstain eller absent) och party_actor_id (partiet ledamoten röstade för, eller null). Varje handling har id, kind, title, dated_on, url och role (signatory när ledamoten skrev handlingen, recipient när frågan ställdes till ledamoten). Rösterna står nyast först, som på ledamotssidan."
        },
        {
          "kind": "text",
          "text": "Ett svar har högst 5000 röster och 2000 handlingar. Finns fler är truncated true, och counts säger hur många det finns. Ledamotssidorna som JSON (/ledamot/<id>.json) är sidindelade som webbsidan. En okänd ledamot ger felet 404."
        },
        {
          "kind": "facts",
          "rows": [
            {
              "label": "Hämta en ledamots alla rader",
              "text": "curl \"https://search.utlovat.se/api/v2/member/a-10\"",
              "href": null,
              "date_on": null
            }
          ]
        }
      ]
    },
    {
      "id": "agentverktyg",
      "heading": "Verktyg för AI-assistenter",
      "blocks": [
        {
          "kind": "text",
          "text": "Läsverktyg för AI-assistenter via MCP (Model Context Protocol, ett protokoll för att låta en assistent anropa verktyg) planeras som ett eget lager ovanpå samma data. Den här sidan beskriver verktygen när de är i drift. Assistenter utan verktyg kan läsa sidorna som Markdown."
        }
      ]
    },
    {
      "id": "v1",
      "heading": "Det v1-kompatibla API:et",
      "blocks": [
        {
          "kind": "text",
          "text": "Valvyn och de som redan använder v1:s programgränssnitt har kvar /api/v1, med samma svar som v1 ger för samma data. Det byggs ur en kompatibel export av de publicerade posterna och ligger tillsammans med valvyn, inte på den här sajten."
        }
      ]
    },
    {
      "id": "takt-cache",
      "heading": "Takt och cache",
      "blocks": [
        {
          "kind": "text",
          "text": "Sidornas .md- och .json-filer får cachas i 300 sekunder och kan läsas från andra webbplatser (Access-Control-Allow-Origin: *). HTML-sidorna cachas inte länge, så att en rättelse syns direkt."
        },
        {
          "kind": "text",
          "text": "Söktjänstens lyckade svar får cachas i 60 sekunder i webbläsaren och 300 sekunder i delade cachar; felsvar cachas inte. Hämta inte hela sajten med sökningen: hämta sidorna eller sajtkartan i stället."
        }
      ]
    },
    {
      "id": "licens",
      "heading": "Licens",
      "blocks": [
        {
          "kind": "text",
          "text": "Uppgifterna och texterna på Utlovat får användas fritt, också i andra verk och i kommersiella sammanhang, enligt licensen CC BY 4.0 (Creative Commons Erkännande 4.0 Internationell)."
        },
        {
          "kind": "text",
          "text": "Ange ”utlovat.se” som källa, länka till licensen och tala om ifall du har ändrat något."
        },
        {
          "kind": "text",
          "text": "Citaten är källornas egna ord. Licensen gäller Utlovats uppgifter och texter, inte de citerade källorna."
        },
        {
          "kind": "text",
          "text": "Licensen gäller inte sajtens programkod."
        },
        {
          "kind": "list",
          "items": [
            {
              "text": "Licensen CC BY 4.0 hos Creative Commons (på svenska)",
              "href": "https://creativecommons.org/licenses/by/4.0/deed.sv",
              "date_on": null
            }
          ]
        }
      ]
    },
    {
      "id": "forbehall",
      "heading": "Begränsningar",
      "blocks": [
        {
          "kind": "notice",
          "label": "Begränsningar",
          "text": "Sidan beskriver det som finns i drift. Det som planeras, som assistentverktygen, är markerat som planerat. Adresser och gränser kan ändras; sidan ändras då med dem."
        }
      ]
    }
  ]
}
