Skip to main content
RTILA Marketplace

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.