API documentation
Every catalogue surface on this site is also available as JSON. The API is
read-only, requires no key, and is versioned: v=1 is the only
defined version, and within a version the response shape is additive-only -
members may be added, existing members never change meaning or disappear.
Breaking changes ship as a new version alongside the old one.
Error envelope
Where an error envelope is produced at all, it carries exactly one member, a
string named error:
{ "error": "unknown category "nope"; known slugs: automation, monitoring, data-entry, scraping, utility, seo, lead-generation, ecommerce, competitive-intelligence, marketing, social-media, market-research, recruiting, real-estate, finance, travel, content, research, productivity, reporting, ai" } GET /api/bots.json
The catalogue dump: every published listing in one unpaginated document, statically materialised at build time. There are no query parameters; consumers filter client-side from the document.
Response envelope
The response carries apiVersion, fields,
generatedAt, count, launcherVersion and
items[]. generatedAt is the build artifact's timestamp
and is never a clock read. Items carry the twenty-one stable catalogue members
(fields is always "summary"); the seven detail members
live on the per-listing route, and project - the authoritative
configuration JSON - is never inlined into the dump.
Headers, caching and validators
Every header on these routes comes from public/_headers: Astro
discards a static endpoint's Response headers at build time, so that
file is the single header owner. Each /api path carries permissive
CORS (Access-Control-Allow-Origin: *), a one-hour public cache
policy, and an Access-Control-Expose-Headers value of
ETag, Last-Modified, Link, Content-Length. Conditional requests (If-None-Match,
304) and Last-Modified are Cloudflare Pages platform
behaviour for static assets; they are not asserted by this site's own code.
What this API does not do: there is no filtering, no pagination
and no query-parameter version negotiation; there is no application-level rate
limit (the CDN is the only shield); and there is no Link header.
Consumers filter client-side from the dump and follow configUrl to
each configuration.
Summary, detail and configuration members
A fields=summary item carries exactly the twenty-one summary
members: slug, url, name,
title, tagline, category,
tags, platforms, version,
updatedDate, botId, price,
priceCurrency, difficulty, targetSites,
updateChannel, requiresInternetAtLaunch,
artifacts, and the three configuration members
configEncoding, configUrl and
configDigest.
A fields=full item additionally carries exactly the seven detail
members: inputSchema, outputSchema,
commandsUsed, changelog, faq,
remote and project.
Two upstream members are permanently excluded and never published under any
version of this contract: remoteVisibility and
requiresEncryptedContent.
configDigest is the lowercase hex SHA-256 of the canonical JSON
form of project (recursive key sort, two-space indent, no trailing
newline, UTF-8). It is null exactly when project is
null, i.e. when configEncoding is
encrypted-string. It equals the digest the provisioning reconcile
control compares against the stored backend configuration, so a consumer can
detect out-of-pipeline drift without diffing JSON. It is a digest of the
canonical form, not of the delivered bytes of any endpoint.
Configuration transparency
For a listing whose configEncoding is plain, the exact
configuration is also readable at the backend configuration-fetch endpoint by
anyone who knows the bot id. This is the documented transparency trade-off
already described on the
security page. Publishing
project through this API therefore discloses nothing new while
making it machine-readable.
Other routes
| Route | Kind | Returns |
|---|---|---|
GET /api/bots.json | static | unpaginated dump of every listing with the twenty-one summary members; the catalogue index (see the section above) |
GET /api/bots/{slug}.json | static, one per listing | the twenty-one summary members plus the seven detail members (inputSchema, outputSchema, commandsUsed, changelog, faq, remote, project); an unknown slug serves the site 404 |
GET /api/bots/{slug}/config.json | static, one per listing | the configuration document only (ApiBotConfigDocument): apiVersion, generatedAt, slug, botId, configEncoding, configDigest, configBytes and project |
GET /api/taxonomy.json | static | categories, tags and platforms, each an array of { slug, count } with in-use counts, materialised at build time |
GET /api/resolved-listings.json | static | build-time provisioning artifact; sitemap-excluded; not part of this public contract and never carrying the contract-excluded members (remoteVisibility, requiresEncryptedContent) |
The backend's liveness and manifest projections are external surfaces served
directly by https://mp.rtila.net (at /healthz and
/d/manifest) with their own cache and validator behaviour; this site
no longer proxies them.