llms.txt
The whole product and API on one screen, for language models and coding agents.
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_profiledstores 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 /healthneeds 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 hasX-Request-Id.422 mode_required(profile withoutmodefor an unknown user),409 not_shown(abandon on ashown: falseslate). Unknown routes answer JSON404 not_found. - Idempotency: events on
event_id; catalog upserts are rerunnable. Never retryPOST /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_profiledrequests carrysession_idand nouser_id. Keys and the signing secret stay on the backend. Report the servedposition(0-based) with every interaction; the engine takeskindand the served position from the logged slate. Give up after 150 ms (the SDKs sendX-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 thepss_secret string. - SDKs 0.4.1, from
github.com/payam-h/patterna-sdk: Gogo get github.com/payam-h/patterna-sdk/[email protected](taggo/v0.4.1); TypeScriptnpm install [email protected](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/[email protected]#subdirectory=python". 0.4.1 types the context fieldsweekday,subscription_tier,tenure_days, the catalog attributes and the events of engine 0.3.1. Engine and contract are 0.3.1 (engine_versionon/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-mintedX-Request-Id,assignment_unit(64 hex, non_profiled),X-Patterna-Tester: 1,context.measured, surfacemin_slots(shown: false) anddevice_resort, interactions checked against the slate, catalogchanged_since,DELETEandlocales,pss_signing secrets, per-event rejection codes, webhook tokens, reason templates with placeholders,pairs_withandmore_about_tag, metricstap_rate/second_item_rate/join_rate/engaged_after_tap. Exploration runs on treatment and on slates outside a holdout (armnone), never on control. - Live since contract 0.2.0 (engine release 0.3): anchored control (
context.control_item_ids, elsefallback.by_anchorfor the anchor, else the surface list;control_sourceon the answer),shown: falsewith no items counted in its arm (abandon answers409 not_shown), fallback fill (fill_count,fill: trueper filled slot),stratify_by: persona,readablefromreadable_sample, per-block ledger rows (by=block),model_versionson impressions, opt-out storing only a salted hash (the hourly job unlinks impressions, keeps interactions, deletes events),PUT /users/{id}/profilewithoutmodefor an unknown user is422 mode_required,context.member_of,coach_product_shown/coach_product_tappedwithproduct_id,conversation_id,position,phase_fitonly withphase_tagson, JSON 404s,engine quickstart. Learners train on arms treatment and none, never control.pairs_withonly 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_itemsand thesession_itemsgenerator,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); generatorstime_fitandformat_fit(silent: never a reason); filtersexclude_dismissed_days(30),exclude_consumed_days(30),paywall_cooldown_days(7),repurchase_days(30),hide_unavailable(true),relevance_floor(0); eventscommunity_post_created,community_reply,community_reaction; truthful reasons with reason keyrecommended. The full list: What the engine uses, and what it refuses. - Start here: Integrate with your AI agent.
Concepts#
- What Patterna is: 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: 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: The three consent modes personalized, cohort and non_profiled, and what each stores, learns from and never stores.
- 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: Plackett-Luce exploration with exact per-position propensities, caps inside the sampler, and SNIPS estimates of a flow on logged traffic.
- The twin: The twin is a tenant simulator for example data and what-if curves at three truth scales; it is never proof.
- 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: 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: Client and engine budgets, fallback versus control, abandoned requests and intention to treat: what counts in the ledger.
- 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: 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: 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: 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: 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: Edit an item's tags in Catalog and approve LLM-proposed health-claim tags under the two-person rule.
- 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: 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: 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: 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: Call Patterna directly from your backend: the three key scopes, a curl for each, and event signing.
- SDK TypeScript: The TypeScript SDK for backends and Expo apps: client, backend proxy, offline queue, consent gate, fallback and signing.
- SDK Go: The Go SDK for a backend request path: timeouts, circuit breaker, fallback, async reports, and a backend drop-in.
- PostHog: Point a PostHog HTTP destination at Patterna; see which events map to what and which fields are dropped.
- Google Analytics 4: Read GA4 events from the BigQuery export with a viewer service account under the same privacy rules as PostHog.
- 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: Import declared quiz answers by random user id and mapped columns; only declared attributes, never health values.
API#
- API overview: Base URL, scopes, error codes, idempotency, rate limits and request ids for the Patterna API.
- Serve scope: Annotated requests and responses for recommendations and interactions under the serve scope.
- Ingest scope: Annotated requests and responses for events, catalog items, tags, status and webhooks under the ingest scope.
- Admin scope: Annotated requests and responses for users, surfaces, flows, experiments, the ledger, exports, keys and audit under the admin scope.
Reference#
- Event types: Every canonical event type with its envelope, props, learner weight, where else it acts and who sends it.
- Reason keys: Every reason key, its default sentence per locale, how flow overrides are keyed, and the placeholders.
- Flow config reference: Every flow config field with its default and valid range, what each generator reads, and the validation errors.
- Error codes: Stable error codes from the API, the SDKs and the panel, with status and what to do.
- Glossary: Short definitions of the terms used across Patterna's docs, panel and API.
- 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: What runs where, which versions are deployed, the job schedule, and what is built or not built.