# llms.txt

> The whole product and API on one screen, for language models and coding agents.

Source: https://staging.patterna.nl/docs/agents/llms

> Patterna is a multi-tenant recommendation service. Your backend asks for a slate per surface and gets item ids, a reason per slot and a request id; it reports seen, click and dismiss by request id. Every surface runs a sticky holdout, and the ledger reports the difference per impression with a 95% interval clustered on users. Three consent modes; `non_profiled` stores no user id.

- API base: `https://api.patterna.nl/v1`. Auth: `Authorization: Bearer <key>`. Tenant comes from the key. Key prefixes: `pk_s_` serve, `pk_i_` ingest, `pk_a_` admin (passes every scope).
- Contract (OpenAPI 3.1): https://staging.patterna.nl/docs/openapi.yaml. Rendered reference: https://staging.patterna.nl/docs/api.
- Scopes: `serve` (`POST /recommendations`, `POST /interactions`), `ingest` (`POST /events`, `/catalog/*`, `/webhooks/*`, `PUT /users/{id}/mode`, `PUT /users/{id}/profile`, `DELETE /users/{id}`), `admin` (reading users, surfaces, flows, experiments, `/proof/*`, keys, audit, settings). `GET /health` needs no key.
- Errors: JSON `{code, message, request_id, details}` with stable codes. Serve: `400 bad_request` (also any unknown JSON field), `401 unauthorized`/`wrong_scope`, `404 unknown_surface`, `409 surface_off`, `422 mode_conflict`, `422 no_candidates`, `429 rate_limited`/`quota_exceeded` (show your own list); interactions: `404 unknown_request`, `422 unknown_item`. Every response has `X-Request-Id`. `422 mode_required` (profile without `mode` for an unknown user), `409 not_shown` (abandon on a `shown: false` slate). Unknown routes answer JSON `404 not_found`.
- Idempotency: events on `event_id`; catalog upserts are rerunnable. Never retry `POST /recommendations`: each call logs an impression.
- Rules: never send email, name, IP, device id, free text, coordinates or health values. User ids are random ids you mint. `non_profiled` requests carry `session_id` and no `user_id`. Keys and the signing secret stay on the backend. Report the served `position` (0-based) with every interaction; the engine takes `kind` and the served position from the logged slate. Give up after 150 ms (the SDKs send `X-Deadline-Ms: 120`; the engine's own budget is 120 ms), show your own list and report the abandonment. The control arm is the surface's editorial list, not a fallback. Deletion is synchronous. Events need no signature on an ingest key; a signature, if sent, is hex HMAC-SHA256 keyed with the `pss_` secret string.
- SDKs 0.4.1, from `github.com/payam-h/patterna-sdk`: Go `go get github.com/payam-h/patterna-sdk/go@v0.4.1` (tag `go/v0.4.1`); TypeScript `npm install patterna-sdk@0.4.1` (unscoped; there is no `@patterna/sdk`); Python from the tag (not on PyPI, by decision): `pip install "patterna-sdk @ git+https://github.com/payam-h/patterna-sdk@v0.4.1#subdirectory=python"`. 0.4.1 types the context fields `weekday`, `subscription_tier`, `tenure_days`, the catalog attributes and the events of engine 0.3.1. Engine and contract are 0.3.1 (`engine_version` on `/health`); the OpenAPI file is binding, a page that disagrees is wrong.
- Live since engine 0.2: `X-Deadline-Ms` / `deadline_ms`, `POST /recommendations/{request_id}/abandon` (`client_abandoned`), client-minted `X-Request-Id`, `assignment_unit` (64 hex, non_profiled), `X-Patterna-Tester: 1`, `context.measured`, surface `min_slots` (`shown: false`) and `device_resort`, interactions checked against the slate, catalog `changed_since`, `DELETE` and `locales`, `pss_` signing secrets, per-event rejection codes, webhook tokens, reason templates with placeholders, `pairs_with` and `more_about_tag`, metrics `tap_rate`/`second_item_rate`/`join_rate`/`engaged_after_tap`. Exploration runs on treatment and on slates outside a holdout (arm `none`), never on control.
- Live since contract 0.2.0 (engine release 0.3): anchored control (`context.control_item_ids`, else `fallback.by_anchor` for the anchor, else the surface list; `control_source` on the answer), `shown: false` with no items counted in its arm (abandon answers `409 not_shown`), fallback fill (`fill_count`, `fill: true` per filled slot), `stratify_by: persona`, `readable` from `readable_sample`, per-block ledger rows (`by=block`), `model_versions` on impressions, opt-out storing only a salted hash (the hourly job unlinks impressions, keeps interactions, deletes events), `PUT /users/{id}/profile` without `mode` for an unknown user is `422 mode_required`, `context.member_of`, `coach_product_shown`/`coach_product_tapped` with `product_id`, `conversation_id`, `position`, `phase_fit` only with `phase_tags` on, JSON 404s, `engine quickstart`. Learners train on arms treatment and none, never control. `pairs_with` only for a recipe or workout with a product, or a community with a document.
- Live since contract 0.3.0: `context.region` (one of the tenant's configured region names; `400 unknown_region`), `context.session_items` and the `session_items` generator, `filters.region_boost` (0.3), `ranker.bandit` (Thompson mixture with logged weights), a monthly request quota (`429 quota_exceeded`).
- Live on engine 0.3.1 ("the signals"): context `weekday`, `subscription_tier`, `tenure_days`; catalog attributes read by the engine (`format`, `duration_min`/`reading_time_min`, `available`/`in_stock`, `expires_at`, `starts_at`, `repurchase_days`); generators `time_fit` and `format_fit` (silent: never a reason); filters `exclude_dismissed_days` (30), `exclude_consumed_days` (30), `paywall_cooldown_days` (7), `repurchase_days` (30), `hide_unavailable` (true), `relevance_floor` (0); events `community_post_created`, `community_reply`, `community_reaction`; truthful reasons with reason key `recommended`. The full list: [What the engine uses, and what it refuses](https://staging.patterna.nl/docs/signals).
- Start here: [Integrate with your AI agent](https://staging.patterna.nl/docs/agents/integrate-with-your-ai-agent).

## Concepts

- [What Patterna is](https://staging.patterna.nl/docs/what-is-patterna): Patterna is a multi-tenant recommendation service that proves its lift with a holdout, gives a reason for every slot and works without a user id.
- [What the engine uses, and what it refuses](https://staging.patterna.nl/docs/signals): The full list of signals: request context, catalog attributes, events with their weights, the nightly artifacts, what is refused, and the rule for what a reason may say.
- [Consent modes](https://staging.patterna.nl/docs/consent-modes): The three consent modes personalized, cohort and non_profiled, and what each stores, learns from and never stores.
- [Proof and the ledger](https://staging.patterna.nl/docs/proof-and-the-ledger): How the sticky holdout, user-clustered intervals, the SRM check and the readable sample make the ledger the only proof.
- [Exploration and propensities](https://staging.patterna.nl/docs/exploration-and-propensities): Plackett-Luce exploration with exact per-position propensities, caps inside the sampler, and SNIPS estimates of a flow on logged traffic.
- [The twin](https://staging.patterna.nl/docs/the-twin): The twin is a tenant simulator for example data and what-if curves at three truth scales; it is never proof.
- [Reasons](https://staging.patterna.nl/docs/reasons): Every slot carries a reason key and a sentence per locale, said only when it is true (else `recommended`), overridable per reason key in the flow config.
- [Surfaces and flows](https://staging.patterna.nl/docs/surfaces-and-flows): Surfaces move through shadow, testers, live and off; flows are versioned configs that you activate with a note and roll back by activating an older version.
- [Timeouts and the ledger](https://staging.patterna.nl/docs/timeouts-and-the-ledger): Client and engine budgets, fallback versus control, abandoned requests and intention to treat: what counts in the ledger.
- [Identity across connectors](https://staging.patterna.nl/docs/identity-across-connectors): Random ids, hashing, PostHog distinct ids, Shopify customers and the assignment unit: one person, one id, never personal data.
- [Data we never store](https://staging.patterna.nl/docs/data-we-never-store): The PII Patterna never stores, the allowlists that enforce it, retention per data class, and how deletion and export work.

## Guides

- [Go live in six steps](https://staging.patterna.nl/docs/go-live-in-six-steps): The setup checklist in six steps, from connecting a data source to a live surface with a holdout and the first readable ledger row.
- [Run a holdout](https://staging.patterna.nl/docs/run-a-holdout): Start a holdout on a surface, size it with the readable sample, and keep it valid until it can be read.
- [Read a ledger row](https://staging.patterna.nl/docs/read-a-ledger-row): A field-by-field walkthrough of one ledger row: rates, difference, interval, sample sizes, readable flag, SRM and revenue.
- [Fix a tag and approve a health claim](https://staging.patterna.nl/docs/fix-a-tag): Edit an item's tags in Catalog and approve LLM-proposed health-claim tags under the two-person rule.
- [Roll back a flow](https://staging.patterna.nl/docs/roll-back-a-flow): Roll a surface back by activating an earlier flow version with a note, or switch Patterna off on your side instantly.
- [Handle a deletion request](https://staging.patterna.nl/docs/handle-a-deletion-request): Delete or export one user's data by random id and follow both timestamps until rows and models are clean.
- [Rotate keys and the signing secret](https://staging.patterna.nl/docs/rotate-keys-and-signing-secret): Replace a scoped API key without downtime, sign events with the pss_ secret string (with test vectors), and rotate the secret.
- [Integrate with your AI agent](https://staging.patterna.nl/docs/agents/integrate-with-your-ai-agent): Step-by-step brief for a coding agent: create keys, load the catalog, set consent, recommend, report interactions, send events and verify with the trace.

## Connectors

- [Backend API](https://staging.patterna.nl/docs/connector-backend-api): Call Patterna directly from your backend: the three key scopes, a curl for each, and event signing.
- [SDK TypeScript](https://staging.patterna.nl/docs/connector-sdk-typescript): The TypeScript SDK for backends and Expo apps: client, backend proxy, offline queue, consent gate, fallback and signing.
- [SDK Go](https://staging.patterna.nl/docs/connector-sdk-go): The Go SDK for a backend request path: timeouts, circuit breaker, fallback, async reports, and a backend drop-in.
- [PostHog](https://staging.patterna.nl/docs/connector-posthog): Point a PostHog HTTP destination at Patterna; see which events map to what and which fields are dropped.
- [Google Analytics 4](https://staging.patterna.nl/docs/connector-ga4): Read GA4 events from the BigQuery export with a viewer service account under the same privacy rules as PostHog.
- [Shopify](https://staging.patterna.nl/docs/connector-shopify): Bring Shopify products in from the public storefront feed or a read-only Admin API token, order history as co-purchase aggregates, HMAC-verified webhooks, and the shop link parameter.
- [Quiz CSV](https://staging.patterna.nl/docs/connector-quiz-csv): Import declared quiz answers by random user id and mapped columns; only declared attributes, never health values.

## API

- [API overview](https://staging.patterna.nl/docs/api-overview): Base URL, scopes, error codes, idempotency, rate limits and request ids for the Patterna API.
- [Serve scope](https://staging.patterna.nl/docs/api-serve): Annotated requests and responses for recommendations and interactions under the serve scope.
- [Ingest scope](https://staging.patterna.nl/docs/api-ingest): Annotated requests and responses for events, catalog items, tags, status and webhooks under the ingest scope.
- [Admin scope](https://staging.patterna.nl/docs/api-admin): Annotated requests and responses for users, surfaces, flows, experiments, the ledger, exports, keys and audit under the admin scope.

## Reference

- [Event types](https://staging.patterna.nl/docs/reference-event-types): Every canonical event type with its envelope, props, learner weight, where else it acts and who sends it.
- [Reason keys](https://staging.patterna.nl/docs/reference-reason-keys): Every reason key, its default sentence per locale, how flow overrides are keyed, and the placeholders.
- [Flow config reference](https://staging.patterna.nl/docs/reference-flow-config): Every flow config field with its default and valid range, what each generator reads, and the validation errors.
- [Error codes](https://staging.patterna.nl/docs/reference-error-codes): Stable error codes from the API, the SDKs and the panel, with status and what to do.
- [Glossary](https://staging.patterna.nl/docs/glossary): Short definitions of the terms used across Patterna's docs, panel and API.
- [Changelog](https://staging.patterna.nl/docs/changelog): What changed in Patterna, newest first: engine 0.3.3 (round 8: the next-item model, content retrieval, real-time sessions) and SDKs 0.4.1 are live.
- [Status](https://staging.patterna.nl/docs/status): What runs where, which versions are deployed, the job schedule, and what is built or not built.
