GRANSKA

Read one law's provisions

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

Reads one law's provisions, each with the pinpoint a profile must cite it by.

Bearer tokenSpends no quotaAnswers with the rate-limit headers once the request is valid

Why you need this before you can create a profile

Knowing that the law you want is 1949:381 is not enough. POST /v1/profiles takes each reviewer's legal reference as three fields — jurisdiction, work and pinpoint — and the pinpoint must be spelled exactly as this library addresses the provision. That spelling exists nowhere but the law itself.

This endpoint is where you get it. Take a pinpoint from the response and send it back verbatim.

Request
curl https://api.granska.cloud/v1/laws/SE/1949:381 \
  -H "Authorization: Bearer $TOKEN"
Response
{
  "jurisdiction": "SE",
  "work": "1949:381",
  "name": "Föräldrabalk (1949:381)",
  "authorityType": "STATUTE",
  "isRepealed": false,
  "repealedAt": null,
  "publishedYear": 1949,
  "ingested": false,
  "provisions": [
    {
      "pinpoint": "kap_6_par_2a§",
      "label": "6 kap. 2 a §",
      "chapter": "6 kap.",
      "part": null,
      "heading": "Om vårdnad, boende och umgänge",
      "parts": [
        {
          "label": null,
          "text": "Vid alla frågor som rör vårdnad, boende och umgänge ska barnets bästa vara avgörande…"
        }
      ],
      "isRepealNotice": false
    }
  ]
}

pinpoint and label are not interchangeable

Read this once and the rest of the endpoint is easy.

  • pinpoint"kap_6_par_2a§". The provision's address. This is what you send us.
  • label"6 kap. 2 a §". The same provision as a lawyer writes it. This is what you show a person.

Nothing translates between them. A reference is matched against the pinpoint by exact equality and is never parsed, so a label sent as a pinpoint is stored without any complaint and then resolves to nothing on every analysis that runs afterwards. The profile looks complete, the law exists, the reviewer appears to be configured, and no reviewer ever reads the provision.

That is not hypothetical: it is what our own published examples told people to do until it was found. Copy the pinpoint field. Never build one by hand, and never assemble work and pinpoint into a single string.

ParameterDescription
jurisdiction
string·path·required
Which legal order the law belongs to. SE and NO resolve today.
work
string·path·required
Which law, exactly as GET /v1/laws spells it. Opaque — never parsed, and never assembled with the pinpoint into one string.
{
  "provisions": [
    {
      "pinpoint": "kap_6_par_2a§",
      "label": "6 kap. 2 a §",
      "chapter": "6 kap.",
      "parts": [{ "label": null, "text": "Vid alla frågor som rör vårdnad…" }],
      "isRepealNotice": false
    }
  ]
}

What a call costs, and when

The first request for a law this library does not hold fetches it from the national source, parses it and stores it. That takes two to five seconds and spends one tick of your organisation's hourly configuration-write floor — the same abuse floor that bounds profile writes. It spends no analysis quota.

Every request for that law during the next 24 hours is answered from storage. It is fast, and it costs nothing at all. So the second caller in your organisation to ask for a law pays nothing, and neither do you when you ask again.

The ingested field tells you which of the two you got: true means this call fetched the law, false means it was already held. The X-RateLimit-* headers are on both answers, so you can read where your floor stands without spending anything to find out.

If the floor is spent you get a 429 — and nothing is fetched, so you are not charged for a law you did not receive.

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1786838400

What comes back

provisions is a fixed list of fields, not the stored record, so nothing we add to our database tomorrow can appear in your response.

Each provision carries its pinpoint, its label, the chapter and heading it sits under, and its text as ordered parts. A part has a label when the source prints one for it — "(f)" on a lettered item — and null when it does not. A part is not separately citable: the pinpoint addresses the whole provision.

chapter is always the level the provision's own address names — 6 kap. for a Swedish provision, Kapittel 5. Stønad ved helsetjenester for Norwegian § 5-15. Some Norwegian acts print an outer division above that chapter, a del, and it comes back as part: "Del IV Ytelser ved sykdom mv.". It is null for every act that prints none, which is every Swedish one. Cite by the chapter — a del is not part of how a provision is addressed. Note that part and parts are unrelated: parts is the provision's own text.

isRepealNotice marks a provision that records a repeal rather than stating a rule. Citing one is almost never what you want.

isRepealed on the law itself says the whole law has been repealed. It is still returned, and still citable — whether that is correct is a judgment about your analysis, not one this endpoint makes for you.

work is opaque. Never parse it, split it or pattern-match on it: its shape differs per jurisdiction and is not part of the contract.

attribution carries the source line that jurisdiction's licence requires be shown wherever its text is displayed, and is null where no such duty exists. Norwegian provisions come from Stiftelsen Lovdata under NLOD 2.0 and always carry one; Swedish provisions never do. Show it wherever you show the provision text, and read it from the response rather than hardcoding the sentence. The same field and the same duty appear on GET /v1/laws.

Errors

A 404 means one of two things and the message says which: there is no such law, or this jurisdiction's laws arrive in bulk archives and asking cannot add one. The second is not a temporary condition — retrying will not help, and the law will appear, or not, at the next bulk refresh.

Neither can happen for a law GET /v1/laws reported as held. A law we hold is always served, including one we have no way to refresh; the 24-hour window decides whether we go and look again, not whether the text is ours to give you.

A 400 means the jurisdiction is not one this API carries. SE and NO resolve today. Ask GET /v1/laws first if you are not sure a law is here.

A 503 means the source was unreachable, or that we could not confirm whether the law has been repealed. In that second case nothing was stored — we would rather answer nothing than store a repeal status we guessed. Retry.

ErrorWhen
400
BAD_REQUEST
The jurisdiction named is not one this API carries.
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.
404
NOT_FOUND
There is no such law, or this jurisdiction's corpus arrives in whole bulk archives so asking cannot add it. The message says which of the two.
429
TOO_MANY_REQUESTS
The organisation has spent its hourly configuration-write floor. Only a real ingest ticks it; a law already held costs nothing. This is an abuse floor and not a plan limit, and no analysis quota is consumed. Not probed: reaching it would mean asking for sixty laws we do not hold.
500
INTERNAL_ERROR
An unexpected server-side failure. Not probable from outside — reaching it means something is wrong.
503
SERVICE_UNAVAILABLE
The source is unreachable, or the register that states whether the law is repealed could not be read — in which case nothing is stored rather than a repeal status being guessed. Retry. Not probed: it needs the upstream source to be down.

The whole journey

  1. GET /v1/laws?jurisdiction=SE&query=… — find the law, and see whether it is held.
  2. GET /v1/laws/SE/{work} — read its provisions and copy the pinpoint you want.
  3. POST /v1/profiles — create the profile citing it.