Base URL and access
Every endpoint lives under https://printingpress.dev/api/v1. The API is public and read-only: it accepts GET, HEAD, and OPTIONS, answers with JSON, and needs no API key, no account, and no signup. There is nothing to configure before the first call. Cross-origin requests from a browser are allowed from any origin.
The catalog it serves is the same registry the HTML pages read, so a slug you see on a detail page is the slug the API knows.
Endpoints
GET https://printingpress.dev/api/v1/clis lists CLIs as summaries. Filter with q (free text, 200 characters or fewer), category (a category slug), and mcp_ready (full, partial, or none). Page with limit (1 to 200, default 50) and offset (0 or more). The body carries items, total, limit, and offset; the Link header carries rel="next" and rel="prev" members when there is another page.
GET https://printingpress.dev/api/v1/clis/{slug} returns the full record for one CLI: every install command, the skill name and URL, the source and README URLs, the Markdown twin, the MCP block when the CLI ships an MCP server, its requirements, and who printed it.
GET https://printingpress.dev/api/v1/categories lists every category with its slug, title, count, and the HTML and API URLs for that shelf.
Every success response carries a weak ETag; send it back as If-None-Match to get a 304 when nothing changed. HEAD returns the same headers as GET with no body.
Quickstart
Search for flight tools and read five summaries: curl -sS "https://printingpress.dev/api/v1/clis?q=flights&limit=5"
Then fetch one record by its slug: curl -sS "https://printingpress.dev/api/v1/clis/flightgoat"
Both commands print JSON to stdout with no key, no header, and no flags beyond the URL.
Rate limits
Every API response carries RateLimit-Policy: "default";q=600;w=60, which reads as 600 requests per 60-second window. The quota is advisory: nothing enforces a counter today, so no request is refused for exceeding it. Stay within it and the policy can become enforced later without breaking a well-behaved client.
Freshness
Responses are cached at the CDN and can trail the library registry by up to eleven minutes; HTML pages refresh sooner. The Cache-Control header on each response states the exact policy. Errors are never cached.
Markdown twins
Every HTML page on this site has a Markdown twin. Ask for it with Accept: text/markdown on the page URL, or fetch it directly at /md/<path>, for example /md/developers for this page. Each CLI record's markdown_url field points at that CLI's twin.
Versioning and deprecation
https://printingpress.dev/api/v1 is the current major version and is stable: fields are added, never removed or renamed, within it. A breaking change ships only under a new major path such as /api/v2, and the old path keeps serving.
When a version or a field is scheduled for removal, responses carry Deprecation and Sunset headers with at least 90 days of notice before the Sunset date. No sunset is scheduled for v1.
The OpenAPI document restates this policy under x-api-lifecycle so a client can read it without visiting this page.
Errors
Every error is an RFC 9457 problem body served as application/problem+json with type, title, status, detail, instance, code, and resolution. The type URI is this page plus #error-<code>, so a client can follow it straight to the section below. detail is fixed per code and never echoes request input. Each code and what to do about it follows.
invalid_limit (400)
The limit parameter was not a plain integer from 1 to 200.
Resolution: Send limit as digits only, from 1 to 200, or omit it to use the default of 50.
invalid_offset (400)
The offset parameter was not a plain non-negative integer of at most nine digits.
Resolution: Send offset as digits only, 0 or greater, or omit it to start from the first item.
invalid_q (400)
The q parameter was longer than 200 characters.
Resolution: Shorten the q parameter to 200 characters or fewer and retry.
invalid_category (400)
The category parameter was not a lowercase slug of letters, digits, and single hyphens.
Resolution: Use a category slug from GET /api/v1/categories, or omit category to search every shelf.
invalid_mcp_ready (400)
The mcp_ready parameter was something other than full, partial, or none.
Resolution: Send mcp_ready as exactly full, partial, or none, or omit it.
cli_not_found (404)
The slug in the path matches no CLI in the catalog.
Resolution: Look up the slug with GET /api/v1/clis?q=<name> and retry with an exact slug.
not_found (404)
The path is under /api but names no resource.
Resolution: Read the OpenAPI document at /openapi.json for the list of valid paths.
method_not_allowed (405)
The request used a method other than GET, HEAD, or OPTIONS.
Resolution: Retry the same URL with a GET or HEAD request.
catalog_unavailable (503)
The catalog could not be loaded from its source. This clears on its own.
Resolution: Retry after the number of seconds given in the Retry-After header.
Discovery
The OpenAPI 3.1 document describes every endpoint, parameter, response, and the Problem schema. The RFC 9727 API catalog at /.well-known/api-catalog points at the document and this page, and every API response links to it with rel="api-catalog". llms.txt is the guidance-first index for coding agents.
Report a problem with the API on the library repository's issue tracker.