OpenAPI specification
Every endpoint OSPulse exposes is described by a single OpenAPI document, published at
https://ospulse.app/openapi.json. It is not a
hand-maintained summary of the API — it is generated from the API itself, which makes it the
authoritative contract and the thing you should build tooling against.
curl -sO https://ospulse.app/openapi.jsonNo authentication is required to fetch it.
What it covers
OpenAPI version3.0.1OptionalCompatible with essentially every generator, linter, and mock server in circulation. If a tool supports OpenAPI 3, it supports this document.
Operations246OptionalEvery endpoint, across packages, repositories, scans, policies, alerts, vulnerabilities, SBOM, CRA, quantum readiness, reports, billing, and administration. Grouped into tags that mirror the sections of the API reference.
Schemas360OptionalRequest and response models, including the shared ApiProblemDetails and
HttpValidationProblemDetails error shapes and every enum — Ecosystem, VulnerabilitySeverity,
PolicySeverity, SbomFormat, and the rest.
Security schemeApiTokenOptionalA single HTTP bearer scheme. Generators surface it as a bearer-token option; see Authentication for how to create the token.
Override the server URL
The servers array in the published document points at a development host. Always set the base
URL explicitly to https://api.ospulse.app in whatever tool consumes the spec. Paths in the
document already carry the /api/v1 prefix, so do not add it twice.
Getting your bearings
Before you generate anything, it is worth reading the shape of the document. A few jq queries
answer most first questions:
# How many operations, and under which tags?
jq '[.paths[] | to_entries[]] | length' openapi.json
jq -r '[.paths[] | to_entries[].value.tags[0]] | group_by(.) | map("\(.[0])\t\(length)") | .[]' \
openapi.json | sort
# Every path in one tag.
jq -r '.paths | to_entries[] | select(.value | to_entries[].value.tags[0] == "Packages") | .key' \
openapi.json
# The exact shape of a response model.
jq '.components.schemas.PackageHealthResponse' openapi.jsonThe interactive reference is generated from it
Explore all endpoints is not written by hand — it renders this same document. That means the reference cannot drift from the API: when an endpoint gains a query parameter, the parameter appears in the reference on the next deploy, without anyone remembering to update prose.
It also means anything you can see in the reference, you can extract from the spec programmatically — request bodies, enum values, status codes, and descriptions all come from the same source.
Generate a client
The most common use of the spec is producing a typed client for your language. Full commands for TypeScript, Go, Java, C#, and Python are on the SDK overview; the short version:
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
-i https://ospulse.app/openapi.json \
-g typescript-fetch \
-o /local/src/ospulseCheck the generation command into your repository — ideally as a script or a make target — so
the client is reproducible rather than a one-off artefact whose provenance nobody remembers.
Run a mock server
A mock lets you build and test an integration before you have credentials, and lets your test suite run without touching production. Prism serves a mock directly from the spec, generating responses from the declared schemas:
npx @stoplight/prism-cli mock https://ospulse.app/openapi.json --port 4010Point your client at it and every endpoint answers with schema-valid data:
curl -s http://127.0.0.1:4010/api/v1/packages?take=2 -H "Authorization: Bearer mock"Prism can also run in proxy mode, forwarding to the real API while validating both the request you sent and the response you got against the contract. This is the fastest way to find out that you are sending a field the API does not accept:
npx @stoplight/prism-cli proxy openapi.json https://api.ospulse.app --errorsMock in tests, proxy in development
Use mock mode in unit tests so they are hermetic and fast. Use proxy mode while you are actively building, so you get real data and a loud complaint the moment your requests stop matching the contract.
Contract testing
If your integration is load-bearing, assert against the contract in CI rather than hoping.
Schema-validate real responses. The cheapest useful test: call the endpoints you depend on and check the responses against the schemas in the spec.
# Fuzz and validate an endpoint group against the contract.
pipx run schemathesis run https://ospulse.app/openapi.json \
--base-url https://api.ospulse.app \
--header "Authorization: Bearer $OSPULSE_TOKEN" \
--include-path-regex '^/api/v1/packages' \
--checks allNever fuzz production with a write-capable token
Schemathesis generates requests, including to POST, PATCH, and DELETE operations. Restrict
it to GET paths, or run it against a mock or a disposable tenant. A read-scoped token is your
safety net — see Authentication.
Lint the document. If you vendor a copy of the spec, lint it so a corrupted or truncated download fails loudly instead of producing a broken client:
npx @stoplight/spectral-cli lint openapi.json --ruleset spectral:oasImport into an API client
Every mainstream HTTP client imports OpenAPI directly, which gives you a working request collection in seconds instead of hand-typing URLs.
Import → Link → https://ospulse.app/openapi.json
Then create an environment with:
baseUrl = https://api.ospulse.app
token = your API token
Set collection Authorization to "Bearer Token" with {{token}} so every
request inherits it, and override the imported server variable with baseUrl.Keep tokens out of committed collections
Bruno collections are files in your repository — put the token in an environment file that is
.gitignored, never inline in a request. The same applies to exported Postman collections,
which embed environment values if you export them with the environment attached.
Keeping generated clients in sync
A generated client is a snapshot. The API keeps moving, so decide deliberately when to catch up rather than finding out at runtime.
Pin the spec you generated from
Store the hash of the document alongside the generated code:
curl -s https://ospulse.app/openapi.json | shasum -a 256 | cut -d' ' -f1 > openapi.sha256Fail CI when the contract moves
A scheduled job that compares the live hash against the pinned one turns "the API changed" from a production surprise into a pull request:
live="$(curl -s https://ospulse.app/openapi.json | shasum -a 256 | cut -d' ' -f1)"
pinned="$(cat openapi.sha256)"
if [ "$live" != "$pinned" ]; then
echo "OpenAPI spec changed — regenerate the client and review the diff"
exit 1
fiDiff for breaking changes, not just any change
Most spec changes are additive and harmless. oasdiff separates the noise from the changes that
will actually break your build:
oasdiff breaking openapi.json <(curl -s https://ospulse.app/openapi.json)If it reports nothing breaking, regenerating is routine. If it does, read Versioning & deprecation before you upgrade.
Regenerate and commit as one change
Regenerate the client, update the pinned hash, and commit them together. Reviewing a generated diff is tedious exactly once; reviewing it never is how a client silently stops matching the API.
Additive by default
New optional fields and new endpoints are added without notice, so generated models should tolerate unknown properties. If your generator has a strict-parsing option, leaving it off for responses will save you an outage.
