Skip to main content
By the end of this guide, every endpoint has a check that reads the response instead of trusting the status code, an authenticated write is created and cleaned up on every run, and a slow endpoint shows as degraded instead of paging anyone.
A Checkly group page named Shop API with four API checks: GET /books, GET /books/{id}, and POST /orders passing, and a slow httpbin endpoint degraded, with run results from N. Virginia and Ireland
To follow along without your own API, clone the sample project. It monitors the catalog API of the Danube demo shop and uses httpbin.org, which echoes requests back, to stand in for an authenticated write endpoint.
To run this guide from your terminal or your coding agent, run npx checkly init in your project first. It installs the Checkly CLI and Checkly Skills for your agent. Then paste the prompt below into Claude Code, Cursor, Codex, or any agent that supports skills. It builds the same setup as this guide, proves it with npx checkly test --record, and stops for your confirmation before npx checkly deploy.
Prompt
The steps below are what the agent does, in the open.

Write down every endpoint

Before writing a check, list what to cover. Different methods on the same path count separately: GET /orders/{id} and DELETE /orders/{id} are two endpoints and two checks. If your API has an OpenAPI spec, the list already exists. The shop’s catalog API has two endpoints:
openapi.yaml
Each operation becomes a check, and each required property becomes an assertion. The spec says /books/1 returns a Book, not which book. The checks below pin the values the spec leaves open.
For a large spec, the web app can import it in bulk. This guide writes the checks as code so they deploy with the API.

Share what every check needs

Every check shares locations, an alert rule, a base URL, and one idea of what “slow” means. Put those in a group so the tenth check costs the same as the first.
__checks__/group.ts
Pointing the group at staging changes one line. Retries are off so a failure lands on the first run. Alerting that doesn’t wake you up for nothing shows when to turn them back on. The project config sets the frequency and tag:
checkly.config.ts

Assert on status, headers, and body

A 200 with an empty array is a broken catalog that a status-code check calls healthy. Assert on the three things the response carries: status, headers, and body. A GraphQL endpoint answers 200 even when the query fails, so also assert that $.errors is empty.
__checks__/catalog.check.ts
Each assertion maps to a way the endpoint breaks:
  • Status code catches the server error and the redirect to a login page.
  • Content-type header catches the HTML error page that ships with a 200.
  • Body length catches the empty list. The first record’s fields catch a serializer that dropped a column.
  • A pinned value catches wrong data. The list check accepts any title because the catalog changes. The detail check names one because book 1 should not.
Body assertions use JSONPath: $.length is the array length and $[0].title the first element’s title. Header names match case-insensitively.

Tell slow from down

Every check so far spreads responseTimes, so each one already separates slow from down. To see where the lines sit, add an endpoint that is always slow. httpbin.org waits two seconds before answering.
__checks__/slow.check.ts
Past one second the run is degraded, which is a warning, not downtime. Past five seconds it fails. The catalog endpoints answer in under 50 milliseconds, so the same thresholds let them slow down twentyfold before anyone hears about it. Set thresholds from what you measure, then tighten them where latency is the product.

Authenticate, create, and clean up

A write endpoint needs a token, a request body no previous run has sent, and something to delete afterward. Setup and teardown scripts wrap the request with that work, so the check stays self-contained.
__checks__/orders.check.ts
The setup script runs before the request. It has a request object whose method, URL, headers, query parameters, and body it can change:
__checks__/orders.setup.ts
The teardown runs after the request and before the assertions. It sees the same request plus a response whose body it can rewrite:
__checks__/orders.teardown.ts
Setup errors abort the check before the request is sent, so a broken token exchange never posts a half-built order, and the result blames the setup rather than the endpoint. Teardown errors do not stop the assertions, so a failed cleanup still reports whether the write worked. Environment variables set in setup live for one run, which is how the order ID reaches the teardown. The last assertion is only true if the teardown ran, which proves the token never reached the stored result. A real client secret goes in an account variable, not in code:
Terminal
Test everything, then deploy:
Terminal
Terminal
The slow endpoint is degraded, not failed. Everything else passes.
Terminal

Verify it works

Simulate a bad data migration. In __checks__/catalog.check.ts, change the expected title from 'Haben oder haben' to 'Parry Hotter' and run npx checkly test --record again. The detail check fails, and the output names the assertion that broke:
Terminal
The status code was fine. Only the body assertion caught it.
A failed GET /books/{id} check result in a Checkly test session, with the assertion JSON body property $.title equals target Parry Hotter marked as failed and the received value Haben oder haben
Change the title back before you deploy again.

Next

Monitor the content your customers need to see: the API returns the right books. Now check that the page built from them shows what customers need, in the right place.

Reference