Build your first API-integration skill
A walkthrough for wrapping a public REST API in a SKILL.md file, from scaffolding to lint to publish, with a worked weather-API example.
Contents
Most useful skills aren’t clever prompts. They’re instructions that tell an agent exactly how to talk to a specific API: which endpoint to hit, which parameters matter, how to read the response, and what to do when it fails. This post walks through building one, from picking an API to publishing the finished skill.
We’ll use a free, no-auth weather API as the running example, since it needs no credentials and the shape of the problem generalizes to anything with an HTTP interface.
Pick an API and read its docs first
Before you write a line of SKILL.md, spend ten minutes with the actual API documentation. You’re looking for four things:
- Base URL and endpoint paths. Is it one endpoint or several? Does it version the URL (
/v1/,/v2/)? - Required and optional parameters. Which ones are mandatory, what are their types, and what do defaults fall back to?
- Response shape. Is it JSON? What are the top-level keys? Are there nested objects an agent would need to traverse to get the actual value?
- Failure modes. What status codes does it return for bad input, missing data, or rate limiting? Does it use HTTP status codes correctly, or does it return 200 with an error field buried in the body?
That last point matters more than people expect. An agent following your skill can’t guess that a 200 response with {"error": "location not found"} means the request failed. You have to spell it out.
For a skill to be worth writing, the API should be stable and boring: predictable endpoints, no exotic auth flow, documented rate limits. Save the OAuth-heavy, pagination-cursor-with-signed-tokens APIs for later.
Scaffold the skill
Install the CLI and generate a starting file:
npm i -g skillmds
skillmd init weather-lookup
This creates weather-lookup/SKILL.md with placeholder frontmatter and a body stub. The directory name and the name field are meant to match, so pick the slug first and let the rest follow from it.
Write the frontmatter
Three fields are read by the parser: name, description, and the optional license. Everything else you add is ignored, so don’t overthink extra keys.
---
name: weather-lookup
description: Looks up current weather conditions for a city or coordinates using a public weather API, and explains how to interpret the response and handle errors.
license: MIT
---
Keep name under 120 characters and matched to the directory. Make description specific enough that an agent can decide relevance without opening the body. “Gets weather data” tells an agent nothing; “Looks up current weather conditions for a city or coordinates” tells it when to reach for this skill instead of some other one.
Write the body: how to actually call the API
This is the part that makes the skill worth having. The body is Markdown instructions, not code that runs. You’re writing a procedure for an agent to follow, in the same way you’d write onboarding notes for a new engineer who has to make this call by hand.
Structure it around the same four things you researched: endpoint, parameters, response handling, and errors.
## Endpoint
Send a GET request to the current-conditions endpoint, passing either a
city name or a latitude/longitude pair as query parameters. Only one of
the two is required.
## Parameters
- `location` (string, optional): city name, e.g. `Riyadh`. Use this or
the lat/lon pair, not both.
- `lat`, `lon` (number, optional): coordinates, used when you need a
specific point rather than a named city.
- `units` (string, optional): `metric` or `imperial`. Defaults to
`metric` if omitted.
## Reading the response
The response is a JSON body. Read the current temperature, conditions
description, and wind speed from the top-level fields the API documents
for its current-conditions response. Confirm the location field in the
response matches what was requested before reporting a value back, since
ambiguous city names can resolve to the wrong place.
## Handling errors and rate limits
- A non-success status code means the request failed outright. Report
this to the user rather than guessing at a value.
- Some APIs return a success status with an error message inside the
body instead of a proper error code. Check for an error or message
field in the body even when the request otherwise looks fine.
- If a request is rejected for making too many calls in a short window,
wait before retrying rather than retrying immediately in a loop.
- Never hardcode an API key in this file. If the API requires one, read
it from an environment variable and reference the variable name here,
not the value.
## Notes
Treat this as a reference for the shape of the request and response.
Field names can differ across providers and API versions, so confirm
against the current docs for the exact endpoint in use before treating
any field name here as final.
A few things worth calling out about that example. It never shows a live curl command or a literal API key. That’s deliberate, and it matters for your lint score.
Why the wording matters for your score
skillmd lint runs a textual security scan over the body, not a sandboxed execution check. It’s pattern matching on the text itself. If your body contains a literal curl https://... command or fetch(...) call, the scanner flags it as a network call. If it contains the phrase “API key” next to something that looks like a credential, it flags reading secrets. Both cost points off your quality score.
This doesn’t mean you can’t explain how to call an API. It means you write the explanation as instructions rather than as executable-looking snippets. Describe the endpoint and method in prose (“send a GET request to the current-conditions endpoint”) instead of pasting a runnable curl line. Reference “an environment variable” instead of writing out a key name that looks like a real secret. The example above documents the same information a runnable snippet would, but reads as a procedure, not a script.
If your score comes back lower than you expect, reread the body for anything that looks like code doing a network call or handling a credential, and rewrite it as a description of the behavior instead.
Lint it
Run the linter before you publish anything:
skillmd lint weather-lookup/SKILL.md
It checks the frontmatter contract (name present and under 120 characters, description present and under 1024 characters), warns if the description is under 20 characters or the license is missing, and warns if the body has no heading or is too short to be useful. It also prints the quality score, which starts at 100 and loses points for lint errors, lint warnings, and anything the security scan flags.
Fix errors first since those block a clean pass. Warnings are optional but worth clearing since they’re free points.
Publish it
Once the lint output looks clean:
skillmd login
skillmd publish weather-lookup/SKILL.md
Publishing submits the skill for a safety review before it shows up in the registry. It’s not instant, so don’t expect it to appear the moment the command returns.
Where to go from here
The weather example above is a stand-in. The pattern is the same for any REST API: read the docs, scaffold with skillmd init, fill in frontmatter that’s specific enough to be useful, and write a body that walks through endpoint, parameters, response handling, and error handling as plain instructions rather than runnable code. Keep credentials out of the file entirely, reference environment variables by name, and let skillmd lint catch what you missed before you publish.
Once you’ve done this for one API, the second one takes a fraction of the time. The scaffolding and the shape of the questions to answer don’t change, only the specifics of the endpoint in front of you.