Skip to content

scotcourts

Search Scottish court cases via the undocumented scotcourts.gov.uk web API (judgments since 1999, fatal accident inquiry determinations). Use when the user asks to find/search Scottish judgments or opinions by keyword, court, or date, needs a scotcourts.gov.uk judgment PDF, or wants to check what Scottish authority exists on a point. Search results are LEADS only — reporting and citation follow the case-law skill standards (big red warning, confirmed paragraph pinpoints, verbatim chunks). Self-learning: appends lessons to learnings.md.

Source: .opencode/skills/scotcourts/SKILL.md — site rebuilt 2026-09-05.


SCTS Case Search (undocumented web API)

The SCTS public site's judgment search is a Vue SPA whose backend is an undocumented Azure autorest API. The API is public — no key, no auth — and is the only machine-readable way to search scotcourts.gov.uk.

API reference (reverse-engineered)

  • Base URL: https://api.pa.web.scotcourts.gov.uk/web (env SCTS_API_BASE overrides; the client default https://api.dv.web.scotcourts.gov.uk/web is the dev host)
  • GET /definition/{contentId} — widget config: configurations, filter fields, dropdown options, limit
  • POST /search — the search; body:
    { "query": "…", "filters": [{"field": "Court", "value": "…"}],
      "page": 1, "limit": 50, "indexType": "Judgments", "category": "" }
    
    Headers: Accept: application/json, Content-Type: application/json; charset=utf-8. indexType must be the config's type"Unknown" or missing returns 400.
  • Date-range filter value serializes as "YYYY-MM-DD|YYYY-MM-DD" (either side empty)
  • Response: {results: […], pagination: {count: {total,start,end}, page: {current,total,limit}}}; each result: title, documentLink (relative — prefix https://www.scotcourts.gov.uk), date, court[], sheriffdom[], judges[], tags[]
  • Widgets: 1414 = Judgments (indexType Judgments; filters Court/Date/AdditionalDate; limit 50; from 1999). 1363 = FAI Determinations (indexType FatalAccidentInquiryDeterminations; filters Sheriffdom/Date/AdditionalDate; limit 12)

Tooling

tools/scotcourts_search.py wraps the API:

  • python <skill>/tools/scotcourts_search.py search --query "<kw>" [--court "Court of Session"] [--date-from YYYY-MM-DD --date-to YYYY-MM-DD] [--page N] [--limit N] [--json] — judgments search (default widget). --content-id fai / --content-id 1363 switches to determinations; FAI uses --sheriffdom instead of --court.
  • … definition [--content-id N] — list a widget's config (courts/sheriffdoms as filter options)
  • … download "<documentLink>" -o out.pdf — fetch the judgment PDF

Workflow

  1. State the legal issue the user needs authority on (case-law skill retrieval protocol step 1).
  2. Run search with keyword (searches title AND narrative) and/or court/date filters. Pagination: page.total tells you if there's more.
  3. For each promising lead: download the PDF, OCR/map it per the okf-ocr skill if scanned or dense (adjudications/FAI determinations are dense — run tools/dense_doc_map.py before capturing holdings).
  4. Reporting is the case-law skill's job. Every case returned to the user follows the case-law format: the big red warning verbatim, ISSUES DECIDED, per-issue HOLDINGS with confirmed paragraph pinpoints and verbatim [N-1][N][N+1] chunks, positions-vs-holdings distinguished, [UNVERIFIED] flags where a pinpoint is not yet confirmed. The API gives you leads + PDFs, not authority — a title and date from the API is [UNVERIFIED] until the judgment text is read and pinpointed.

Gotchas

  • indexType is required and must match the config type (400 otherwise) — the tool sets it from the definition automatically.
  • limit above the widget's configured limit is clamped server-side (50 for judgments).
  • Results have no neutral citations or paragraph numbers — citations come from reading the PDF.
  • The site also has /geocode, /gazetteer, /locations endpoints used by the court locator — not needed for case search.

Self-learning

learnings.md sits next to this SKILL.md. Read it before searching; append dated lessons after (API quirks, filter behaviours, widget changes). Never delete old entries.