# Creative DTC: read-only discovery contract

Version: 4.1.0. This is an editorial reference catalog, not a storefront. It does not sell products, take payment, or verify live inventory.

## Start here

- `/api/products.json`: all 83 records, ascending numeric ID; no pagination, authentication, or hidden truncation.
- `/api/products/{slug}.json`: one stable product record.
- `/api/products/{slug}.md`: the same product as readable Markdown.
- `/api/tags.json`: editorial design lenses and their definitions.
- `/api/catalog.schema.json`: JSON Schema 2020-12 for the complete catalog.
- `/openapi.json`: OpenAPI 3.1 read-only interfaces.
- `/index.html`: complete product links and summaries in initial HTML, usable without JavaScript.
- `/about.html`: editorial scope and photography attribution.

Resolve relative links against the origin serving this document. The local preview is not a public production origin.

## Search and filtering

Browser discovery URL: `/index.html?q=toothpaste&category=personal-care&tags=solid,concentrate&sort=relevance&view=index`.

`q` accepts up to 180 characters and matches all normalized words, with explicit common synonyms (for example portable → pocket, packable, compact, travel; waterless → solid, bar, tablet, sheet). Exact product/brand matches rank ahead of form matches, then description matches. Accents and punctuation are normalized. Search is client-side; the static JSON URLs do not implement query parameters. Fetch the catalog and filter records locally when not using a browser.

Categories: `personal-care`, `home`, `food-drink`, `wellness`, `gear`, `fitness`, `tech`, `kids-family`, `pet`, `apparel`. Special browser collections: `__shortlist` (editor_rank 1–10) and `__saved` (signed-in user's collection).

`tags` is a comma-separated set of IDs from `/api/tags.json`. All selected tags must match, combined with category and search. Tag absence means unclassified, not that a product lacks a property. The labels are editorial groupings, not sustainability, medical, or safety certifications.

`sort`: `relevance` (default; numeric ID when no query), `editor` (ranked entries first), `brand`, or `name`. Ties use numeric ID. Shortlist uses editor rank unless an explicit alphabetical order is chosen. `view=index` changes presentation only. Unknown filter IDs produce a visible notice and are ignored; valid remaining constraints stay active. All matching results are present; there is no pagination.

## Facts, provenance, and freshness

Each record has stable `id` and `slug`, brand, category, form, three editorial summary points, photography credit/source, tags, catalog date, and explicit unknown fields. `availability: "unknown"` and `price: null` mean unknown, never out of stock or free. No variant specifications or independent claim testing are supplied. Brand descriptions can change; consult the linked brand before making purchasing or suitability claims.

Catalog date: 2026-10-13. Updates are manual; there is no promised refresh interval or live inventory feed. A content-derived `revision` changes when catalog records change. The bundled Node server supplies ETags and conditional GET. Other hosts control their own HTTP cache headers; the revision remains portable.

## Access and actions

Public HTML, JSON, Markdown, and machine docs support read-only factual retrieval by interactive agents and search tools. No authenticated partner integration, MCP server, checkout, or order API is provided. robots.txt describes crawler directives only; it is not permission to bypass authentication. No training license is granted for third-party photography or brand content.

Private saved collections use Supabase authentication and owner-scoped row-level security. A user must authorize saving/removing their products. Do not bypass sign-in, ask for service-role keys, or represent the public catalog API as an authenticated mutation interface. Missing account setup is explicitly shown in the UI. Failed saves remain unsaved and offer retry guidance. Repeated save actions toggle state; they are not an idempotent public API.

Missing resources return HTTP 404 on the bundled server. Use the full catalog to recover a valid slug. Authentication, SMTP delivery, and production isolation require the launch verification described in the project's LAUNCH.md; public documentation is not proof of live account readiness.

## Browser controls

Search products; Filters; Product features; Sort products; Compact view (toggle); Share search; Save/Unsave [product name]. Native form controls, named main regions, visible focus, live result counts, and URL state support browser automation without screen coordinates. Keyboard: `/` focuses search; Escape clears the focused search field or closes Filters. Every product has a canonical page, JSON record, and source attribution.

## HTTP consumer contract (bundled Node server)

GET and HEAD return the same status and headers; HEAD has no body. Public data routes under `/api/`, plus `/openapi.json`, `/agent-guide.md`, and `/llms.txt`, allow anonymous cross-origin reads (`Access-Control-Allow-Origin: *`) and expose ETag. OPTIONS returns 204 for preflight. Never send credentials to these public interfaces. Other hosts must be tested separately.

JSON files, including `/api/catalog.schema.json`, use `application/json`. Unknown API resources return 404 JSON with `{error:{code,message},catalog:"/api/products.json"}`. Malformed encoding returns 400, unsupported methods 405 with Allow, and server read failures 500. Missing human pages return HTML. Check status and content type before parsing. The server accepts exact, weak, wildcard, and comma-separated If-None-Match validators; 304 has no body. Cache-Control is no-cache except account pages (no-store). Store the body with its validator and reuse it after 304. Do not confuse the portable catalog revision with the HTTP validator.

`/api/categories.json` defines category IDs and counts. `/assets/api-example.js` is a runnable consumer module; API docs show its full source. `verified_on` is a legacy snapshot date, not proof every claim was independently checked. Per-source checked_at can be null. Additional response fields may appear; consumers should ignore unknown fields and validate fields they rely on.

## Editorial articles

`/journal/index.html` links all ten initial field notes in static HTML. `/api/articles.json` lists their HTML, Markdown, and original SVG diagrams; `/journal/feed.xml` provides RSS. Articles are AI-assisted desk analysis, with explicit evidence limits, catalog examples, and brand reference links. Interpretations are not product-performance tests. Structured BlogPosting metadata matches visible titles and dates. Discovery files assist retrieval; they do not establish search-engine inclusion.

Product feature links toggle that feature while retaining the current query, category, and other features. The Filters panel exposes Clear all and a live Show products action; Clear all resets the query, category, and features while retaining sort and view.
