Read one law's provisions
https://api.granska.cloud/v1/laws/:jurisdiction/:workReads one law's provisions, each with the pinpoint a profile must cite it by.
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.
curl https://api.granska.cloud/v1/laws/SE/1949:381 \
-H "Authorization: Bearer $TOKEN"{
"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.
| Parameter | Description |
|---|---|
jurisdictionstring·path·required | Which legal order the law belongs to. SE and NO resolve today. |
workstring·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.
| Error | When |
|---|---|
400BAD_REQUEST | The jurisdiction named is not one this API carries. |
401UNAUTHORIZED | The Authorization header is missing, is not a readable bearer token, or names no tenant. |
401TOKEN_EXPIRED | The access token was issued by this gateway and has since expired. Not probed: it needs a token older than its own lifetime. |
404NOT_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. |
429TOO_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. |
500INTERNAL_ERROR | An unexpected server-side failure. Not probable from outside — reaching it means something is wrong. |
503SERVICE_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
GET /v1/laws?jurisdiction=SE&query=…— find the law, and see whether it is held.GET /v1/laws/SE/{work}— read its provisions and copy thepinpointyou want.POST /v1/profiles— create the profile citing it.