OSPulse

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.

bash
curl -sO https://ospulse.app/openapi.json

No authentication is required to fetch it.

What it covers

OpenAPI version3.0.1Optional

Compatible with essentially every generator, linter, and mock server in circulation. If a tool supports OpenAPI 3, it supports this document.

Operations246Optional

Every 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.

Schemas360Optional

Request and response models, including the shared ApiProblemDetails and HttpValidationProblemDetails error shapes and every enum — Ecosystem, VulnerabilitySeverity, PolicySeverity, SbomFormat, and the rest.

Security schemeApiTokenOptional

A 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:

bash
# 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.json

The 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:

bash
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate \
  -i https://ospulse.app/openapi.json \
  -g typescript-fetch \
  -o /local/src/ospulse

Check 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:

bash
npx @stoplight/prism-cli mock https://ospulse.app/openapi.json --port 4010

Point your client at it and every endpoint answers with schema-valid data:

bash
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:

bash
npx @stoplight/prism-cli proxy openapi.json https://api.ospulse.app --errors

Mock 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.

bash
# 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 all

Never 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:

bash
npx @stoplight/spectral-cli lint openapi.json --ruleset spectral:oas

Import 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.

text
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:

bash
curl -s https://ospulse.app/openapi.json | shasum -a 256 | cut -d' ' -f1 > openapi.sha256

Fail 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:

bash
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
fi

Diff 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:

bash
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.

Next steps