GRANSKA

Search a jurisdiction's laws

GEThttps://api.granska.cloud/v1/laws

Searches a jurisdiction's catalogue of laws, and says which of them this corpus holds.

Bearer tokenSpends no quota

What this answers that a public register does not

You can find an SFS number on riksdagen.se. What you cannot find there is whether a citation to it will resolve here — and that is the one thing a profile needs to be accepted.

That is the held field on every hit. true means the law is in the library and POST /v1/profiles will accept a reference to it. false means it is not, yet.

Searching is free. It spends no analysis quota and counts against no floor, so you may call it as often as your integration needs. That is deliberate: a caller who cannot search cheaply guesses citations instead, against a metered write endpoint, and that is worse for everyone.

Request
curl -G https://api.granska.cloud/v1/laws \
  --data-urlencode "jurisdiction=SE" \
  --data-urlencode "query=föräldrabalk" \
  -H "Authorization: Bearer $TOKEN"
Response
{
  "jurisdiction": "SE",
  "fetchable": true,
  "laws": [
    {
      "jurisdiction": "SE",
      "work": "1949:381",
      "title": "Föräldrabalk (1949:381)",
      "displayLabel": "Föräldrabalk (1949:381)",
      "issuingBody": "Justitiedepartementet L2",
      "repealedAt": null,
      "held": true
    },
    {
      "jurisdiction": "SE",
      "work": "1981:1292",
      "title": "Förordning (1981:1292) om vårdnadsutredningar",
      "displayLabel": "Förordning (1981:1292) om vårdnadsutredningar",
      "issuingBody": "Justitiedepartementet",
      "repealedAt": null,
      "held": false
    }
  ]
}

The parameters

jurisdiction says which legal order to search. SE and NO resolve today. Any other value is refused with a 400 that names what is available — never an empty list, because an empty list would say that law does not exist when the truth is we have not integrated that country.

query is matched against each law's number and its title. Two characters minimum. A shorter query is a 400 rather than a list of everything.

ParameterDescription
jurisdiction
string·query·required
Which legal order to search. SE and NO resolve today; anything else is refused by name.
query
string·query·required
Free text matched against each law's number and title. At least two characters.
limit
integer·query
How many hits to return, between 1 and 50. Defaults to 50.
{
  "jurisdiction": "SE",
  "fetchable": true,
  "attribution": null,
  "laws": [
    {
      "jurisdiction": "SE",
      "work": "1949:381",
      "displayLabel": "Föräldrabalk (1949:381)",
      "held": true
    }
  ]
}

Two title fields, and which one to show

displayLabel is the one to put in front of a person. It is a single clean line, formatted for that purpose.

title is the register's own text, untouched — which means hard line breaks inside it, the law's number repeated within it, and several lines of it on older acts. It is published because it is the authentic wording and some integrations need exactly that. It is not published because it is presentable.

We do not publish an instrument type — whether something is a lag, a förordning or a författning — as a separate field, and we will not add one. The Swedish register does not state it: every row of it is labelled SFS, which names the register rather than the kind of instrument. The only way to produce that field would be to guess it from the first word of a Swedish title, and a legal fact inferred from a text string is not a legal fact. A reader still sees it, because displayLabel reads "Förordning (1982:47) om…". We show it; we never assert it.

repealedAt is a date when the law has been repealed and null when it has not. A repealed law is still returned and still citable — that is a judgment for you to make, not one for a search endpoint.

attribution is a licence condition, not a courtesy

Some registers are licensed data, and the licence requires that the source be named wherever the data is shown. attribution carries the exact line that register demands, and it is null where no such duty exists.

Norway's catalogue is published by Stiftelsen Lovdata under NLOD 2.0, so a Norwegian search answers:

{
  "jurisdiction": "NO",
  "fetchable": true,
  "attribution": "Inneholder data under Norsk lisens for offentlige data (NLOD) tilgjengeliggjort av Stiftelsen Lovdata.",
  "laws": []
}

Sweden's register carries no such condition and always answers null.

Show the line wherever you show the data. The duty travels with the text: it reaches your product the moment you display a Norwegian title or provision to a user, and passing the data on without it is a breach of the licence we hold. Read the field rather than hardcoding the sentence — a register's required wording is theirs to change, and a hardcoded copy is one that silently stops being correct.

held: false means one of two things, and fetchable says which

fetchable sits on the response, not on each hit, because it is a fact about the jurisdiction's source rather than about any one law.

  • fetchable: true — ask for the law with GET /v1/laws/:jurisdiction/:work and it will be fetched, parsed and stored on the spot. held: false here means not yet. Both Sweden and Norway work this way.
  • fetchable: false — that jurisdiction's corpus arrives as whole bulk archives with no way to request a single law. held: false here means asking will not change it. What is absent stays absent until the next bulk refresh.

Errors

Every refusal here is a 400, and every one of them names what was wrong with the request. There is no 404: a search that matches nothing is a successful search with an empty laws array. A search that could not be performed at all is an error, and the two are never confused.

ErrorWhen
400
BAD_REQUEST
jurisdiction is missing or is not one this API carries, query is missing or shorter than two characters, or limit is not a whole number between 1 and 50.
401
UNAUTHORIZED
The Authorization header is missing, is not a readable bearer token, or names no tenant.
401
TOKEN_EXPIRED
The access token was issued by this gateway and has since expired. Not probed: it needs a token older than its own lifetime.
500
INTERNAL_ERROR
An unexpected server-side failure. Not probable from outside — reaching it means something is wrong.

Send it without writing a client

If your organisation already has an account, an administrator can call this from the API tester at /admin/api-tester without spending any quota.