List or resolve legal sources
https://api.granska.cloud/v1/snippetsLists the legal sources this tenant may use, or resolves exactly one of them.
Two modes, and they are mutually exclusive
Send no query parameters and you get the list: every legal source your tenant may cite, both the
shared ones and any your organisation authored itself. Add includeText=true and each entry carries
its body as well as its metadata.
Name a source and you get that one source instead, projected down to six fields. There are two ways to name one, and they cannot be combined:
snippetKey— the stable key of an authored source.jurisdiction+work+pinpoint— a provision of published law, given as three separate fields.
A request carrying snippetKey together with any of the reference fields is a 400. So is a
reference missing any of its three parts. The endpoint never guesses which kind of identifier you
have, because the two are governed by different authorities and a wrong guess would answer with the
wrong law — and the caller always knows: a delivered analysis states both explicitly beside each
citation.
This is the lookup behind a clickable citation in a report. includeText applies to the list only.
Both modes start from an identifier you already have. To go the other way — from a subject to a law
you could cite — search the catalogue with GET /v1/laws and read its
provisions with GET /v1/laws/:jurisdiction/:work.
# List everything this tenant may use:
curl "https://api.granska.cloud/v1/snippets" \
-H "Authorization: Bearer $TOKEN"
# Or resolve exactly one provision. A pinpoint is the provision's node id, not its
# printed label, and it can carry characters that must be percent-encoded in a query
# string — let curl do it with -G --data-urlencode rather than pasting it raw:
curl -G "https://api.granska.cloud/v1/snippets" \
--data-urlencode "jurisdiction=SE" \
--data-urlencode "work=1993:387" \
--data-urlencode "pinpoint=par_7§" \
-H "Authorization: Bearer $TOKEN"{
"snippets": [
{
"id": "snip_3f0a",
"tenantId": "SYSTEM",
"snippetKey": "lss-7-goda-levnadsvillkor",
"name": "7 § LSS — goda levnadsvillkor",
"source": "SFS 1993:387",
"authorityType": "STATUTE",
"validFromYear": 1994,
"validToYear": null,
"updatedAt": {
"_seconds": 1781164800,
"_nanoseconds": 0
},
"normLevel": "Lag",
"legalWeight": "BINDING"
}
]
}Naming one source
Note that any one of jurisdiction, work or pinpoint switches the endpoint into single-source
mode. A stray ?work= on a call you meant as a list is therefore a 400 rather than a list — the
endpoint would otherwise have to decide silently that you did not mean it.
Never assemble the three parts into a key string like SE/2009:400/kap_26_par_1§ and send that. The
projection to such a string is one-way by design and has no inverse; it exists so the database can
index on it, not so it can be read back.
Treat work and pinpoint as opaque: never parse them, pattern-match on them or split them.
Their shape differs per jurisdiction and is not part of the contract — see
the anchor fields.
| Parameter | Description |
|---|---|
includeText"true" | "false"·query | Set to "true" to get each source's full text rather than metadata alone. |
snippetKeystring·query | Resolves the one authored source with this key instead of listing. Cannot be combined with the reference fields. |
jurisdictionstring·query | Which legal order the provision belongs to. Given together with work and pinpoint, resolves one statute provision. |
workstring·query | Which law. Given together with jurisdiction and pinpoint, resolves one statute provision. |
pinpointstring·query | Where in the law — the id the provision is addressed by ("par_7§"), never the label it is printed as ("7 §"). Given together with jurisdiction and work, resolves one statute provision. |
{
"snippet": {
"name": "Barnets bästa",
"source": "SoL 5 kap. 1 §",
"content": "När åtgärder rör barn ska barnets bästa särskilt beaktas...",
"authorityType": "STATUTE",
"validFromYear": 2024,
"validToYear": null
}
}
What the list returns, and what it no longer returns
The list is a fixed field list, not the stored document: id, tenantId, snippetKey, name,
source, authorityType, validFromYear, validToYear and updatedAt, plus text, content and
anchors when includeText=true. An internal field added to the database tomorrow cannot appear in
your response, which used to be exactly what happened.
Two fields in the list are deprecated — normLevel and legalWeight. They are no longer stored;
they are computed on the way out so that nobody had to migrate in the same release as the rename.
Read Deprecated fields before using either, and read authorityType
instead.
The single-source response carries neither. That mode was introduced with the new names, so there is no client with an old expectation to keep — and what was never published never needs deprecating.
validFromYear and validToYear are display metadata only. Nothing in the engine selects a version
by them.
updatedAt is stamped when a source is written, is absent on sources that have never been rewritten
since import — that is not a fault — and is serialised as a raw database timestamp rather than ISO
8601, the same quirk as on GET /v1/jobs/:jobId.
Errors
404 does not distinguish "no such source" from "not yours". A key belonging to another organisation
answers exactly as a key that never existed, so this endpoint cannot be used to probe what anyone else
holds.
| Error | When |
|---|---|
400BAD_REQUEST | snippetKey was combined with a reference field, or a reference was given without all three of jurisdiction, work and pinpoint. |
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 | No source matches, or none this tenant may see. The gateway does not distinguish the two. |
500INTERNAL_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 browse the catalogue from the API
tester at /admin/api-tester without spending any quota.