The request is just a description; nothing is sent until req_perform()
Perform and check the status
resp <-req_perform(req)resp
<httr2_response>
GET https://api.kolada.se/v3/municipality?title=Stockholm
Status: 200 OK
Content-Type: application/json
Body: In memory (155 bytes)
resp_status(resp)
[1] 200
resp_status_desc(resp)
[1] "OK"
Parse the JSON body
body <-resp_body_json(resp)str(body, max.level =2)
List of 4
$ values :List of 2
..$ :List of 3
..$ :List of 3
$ next_url : NULL
$ previous_url: NULL
$ count : int 2
resp_body_json() parses JSON into a nested R list
Use str() or View() if you want to click through
Walk the list to find what you want
str(body$values, max.level =2)
List of 2
$ :List of 3
..$ id : chr "0001"
..$ title: chr "Region Stockholm"
..$ type : chr "L"
$ :List of 3
..$ id : chr "0180"
..$ title: chr "Stockholm"
..$ type : chr "K"
[1] "Antal nystartade företag delat med antalet tusen invånare, 16-64 år, föregående år. Ett nystartat företag definieras enligt Eurostat rekommendation som ett helt nystartat företag frånräknat olika former av ombildningar av existerade företag. Enskilda näringsidkare vilka inte registrerat firmanamn hos Bolagsverket ingår. Data bygger på bearbetningar av SCB:s företagsregister. Källa: Tillväxtanalys"
N00999: new firm starts per 1000 inhabitants aged 16-64
The catalogue endpoint returns metadata, not data values
Read the description and unit before you trust the numbers
id label
<char> <char>
1: TAB638 Population by region, marital status, age and sex. Year 1968-2024
2: TAB5557 Population by region, marital status, age and sex. Year 2025
3: TAB2819 Mean population by region, marital status, age and sex. Year 2006-2024
period
<char>
1: 1968–2024
2: 2025–2025
3: 2006–2024
Fetch table metadata
TAB638 = “Population by region, marital status, age and sex”
Read the documentation. Some APIs require it (Nominatim, met.no)
Cite the source in any output that uses the data
Wrapping API access in an Agent Skill
Web Scraping
What is an API?
Calling APIs from R: Kolada
Example 2: SCB (PxWebApi v2, GET)
Authentication and Respectful Use
Wrapping API access in an Agent Skill
Wrapping Up
From an API call to a skill
An agent skill is a small package that tells an agent
what a capability does
when to reach for it
how to call it
Folder with a SKILL.md runbook plus helper R scripts
Same idea as L5: Skill is now pointed outward at an API
What a fetch-scb skill should do
Help any caller — agent or human — pull statistics from SCB without re-learning the API every time.
Search for table candidates - return candidate TAB#### IDs and labels
Inspect a table ID - list (eliminable/not) dimensions, codes
Slice a table ID - fetch and parse into a tidy data.table
Iterate politely — sleep between calls, retry on fail, cache repeats
Cite — return the table ID, ContentsCode, API call
SKILL.md — the runbook the agent reads
---name: fetch-scbdescription: Search SCB tables and fetch tidy slices as R data.table. Use for Swedish official-statistics questions by region, year, or demographic.---# fetch-scbR scripts for searching, querying, and parsing live in `scripts/`:- `scripts/scb_search.R` defines `scb_search_tables(...)` for finding relevant tables by keyword- `scripts/scb_meta.R` defines `scb_metadata(...)` for fetching data codes and slicing dimensions- `scripts/scb_query.R` defines `scb_query(...)` for fetching and parsing tidy data## Workflow1. If the user names a topic, search with `scb_search_tables(...)`. Show top hits, ask which to use.2. `scb_metadata(...)`: confirm metric (`ContentsCode`) and dimensions.3. `scb_query(...)`: with `selections` listing only the dimensions to pin...
One helper script per capability, each callable from R or from the agent’s tool layer
Helpers are normal R functions — write tests, run them at the REPL, ship them in the skill
A skill grows institutional memory
SKILL.md is where that knowledge lives — versioned with the project, re-read on every call
More wisdom over time — append, don’t rewrite
## Gotchas- **Labour-market series breaks in 2022.** Pre-2022 lives in one table, 2022+ in another. The series is *not* seamless — keep a `source_table` column so the join is auditable.- **414 URI Too Long.** `valueCodes[Alder]` with many ages overflows the URL. Split age ranges into chunks of ≤ 25 codes and `rbindlist`.- **Income is in price-base amounts (`pbb`)**, not SEK. Join the yearly`prisbasbelopp` to convert. Real-terms comparisons need the index too.
Why a skill, not just a script
Discoverable: the agent finds it when relevant
Interactive: the agent can ask questions and help you search
Single source of truth: API quirks and rate-limit rules in one place
Adaptable: the agent can adjust parameters on the fly (e.g., “fetch 2010–2020 instead of just 2022”)
Transferable: same shape works for fetch-eurostat, fetch-fred, fetch-worldbank
Wrapping Up
Web Scraping
What is an API?
Calling APIs from R: Kolada
Example 2: SCB (PxWebApi v2, GET)
Authentication and Respectful Use
Wrapping API access in an Agent Skill
Wrapping Up
Main takeaways
Look for an API before you scrape — and look for a hidden API before you give up