Patterna Docs

llms.txt

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

Developers 8 min read View as Markdown

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/[email protected] (tag go/v0.4.1); TypeScript npm 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 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.
  • 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.
esc
  • Type to search every page, heading and code sample.