API reference
Generated from the frozen OpenAPI contract (v1.0.0). All routes live under /v1; dashboard routes authenticate with a Clerk session JWT, SDK ingest routes with a per-org API key (X-API-Key).
Endpoints
GET/v1/experiments
List experiments for the caller's org
Returns every experiment the caller's org can see (latest configuration version each). Use it to populate the dashboard list, then drill into an id for its computed results.
auth: clerkJwt · responses: 200, 401
POST/v1/experiments
Create an experiment (a new version is minted)
Creates an experiment from a config (variants, allocation weights, metrics), minted at version 1. The `salt` and `bucket_count` you set here freeze how users are bucketed, so keep them stable for the life of the experiment. Returns the stored experiment with its id.
auth: clerkJwt · responses: 201, 400, 401
GET/v1/experiments/{id}
Get an experiment
Fetches one experiment (its latest version) by id, scoped to the caller's org.
auth: clerkJwt · responses: 200, 404
PUT/v1/experiments/{id}
Update an experiment (mints a new version; sticky assignments preserved)
Applies a config change by minting a new version. Because the salt and bucketing are preserved, users already assigned keep their variant — in-flight traffic is never reshuffled.
auth: clerkJwt · responses: 200, 400
POST/v1/assign
Resolve a variant for a user (SDK ingest plane)
Server-side variant resolution for callers that can't run the SDK's local bucketing (e.g. a non-supported language). Deterministic and sticky. Prefer the SDK's in-process `assign` on hot paths — it needs no network round-trip.
auth: apiKeyPublishable | apiKeySecret · responses: 200, 401, 429
POST/v1/events
Ingest a batch of events (SDK ingest plane, async write path)
Asynchronous write path for `exposure`, `model_call`, and `business_event` records. Returns immediately with an ack and the current `config_version` (a staleness hint the SDK uses to refresh). The SDK batches, retries, and spills offline for you — call `track`, not this.
auth: apiKeyPublishable | apiKeySecret · responses: 202, 401, 429
POST/v1/events/import
Bulk import historical events (server-side only)
Backfill historical events as newline-delimited JSON using a secret key (server-side only, never a browser). Use it to seed an experiment from data you already collected. See the "Bring your own data" guide for the field mapping.
auth: apiKeySecret · responses: 202
GET/v1/config
Fetch the current experiment config (versioned, poll-friendly)
SDKs and the assignment service poll this on an interval using `If-None-Match`. An unchanged config returns `304`. The org is derived from the API key, never a query param.
auth: apiKeyPublishable | apiKeySecret · responses: 200, 304
GET/v1/experiments/{id}/results
Get computed results for an experiment
Returns the latest per-metric results: effect + 95% CI, raw and FDR-corrected p-values, the test used, the per-arm value distribution, and the SRM gate status. Accepts an optional `day` query parameter to read one run — an ISO date (nightly experiment-day) or a stored manual run's `manual-<ISO instant>` label; the response's `available_days` lists every day and permanently stored manual run with computed rows and `computed_for` names the served run. `GET /v1/experiments/{id}/traffic` (additive route) serves the daily exposure counts per variant for the traffic timeline. Responds `404` until the daily pipeline has produced results (the dashboard shows a "collecting" state meanwhile).
auth: clerkJwt · responses: 200, 404
POST/v1/keys
Issue or rotate an org API key
Issues or rotates a `publishable` (safe client-side, write-only) or `secret` (server-side) org key. The key is returned once and never shown again — store it immediately. Rotating invalidates the previous key of that scope.
auth: clerkJwt · responses: 201
POST/v1/business-events
Receive a business event via HMAC-signed webhook
Ingests a downstream business outcome (conversion, revenue, retention) via an HMAC-signed webhook, so post-experience metrics can be attributed back to the experiment and variant.
auth: hmacSignature · responses: 202, 401
POST/v1/webhooks/clerk
Clerk identity-sync webhook (Svix-signed)
Upserts user/organization/membership changes into LLMJury's Postgres (internal UUIDs with `clerk_*` external-reference columns; CONVENTIONS §11). The Svix signature is verified.
auth: svixSignature · responses: 204, 401
GET/v1/billing/summary
The caller org's plan and subscription state
Returns the org's current plan (`free`/`pro`/`business`/`enterprise`), its Stripe subscription status, and whether billing is available on this environment. An org that has never checked out is the free tier.
auth: clerkJwt · responses: 200
POST/v1/billing/checkout-session
Start a Stripe Checkout for a paid plan (admin-only)
Creates a Stripe-hosted Checkout Session for the `pro` or `business` subscription and returns its URL; the browser is redirected there, so no card data ever transits LLMJury. The completed purchase arrives back via the Stripe webhook.
auth: clerkJwt · responses: 200, 409
POST/v1/billing/portal-session
Open the Stripe Billing Portal (admin-only)
Creates a Stripe Billing Portal session (manage payment method, cancel, invoices) for an org that has completed a checkout, and returns its URL. 409 when no billing account exists.
auth: clerkJwt · responses: 200, 409
POST/v1/webhooks/stripe
Stripe billing webhook (signature-verified)
Applies subscription lifecycle events (`checkout.session.completed`, `customer.subscription.created/updated/deleted`) to the org's plan. The `Stripe-Signature` header is verified against the endpoint secret; processing is an idempotent upsert, so Stripe retries are safe. Other event types are acknowledged and ignored.
auth: stripeSignature · responses: 204, 401
Schemas
| Schema | Required fields | Description |
|---|---|---|
| Problem | — | RFC 9457 problem details (application/problem+json). |
| AllocationSlice | variant, weight | — |
| Experiment | — | A persisted experiment — its config plus server-set timestamps. |
| ExperimentConfig | name, salt, bucket_count, allocation, metrics | The versioned experiment config SDKs poll. Embeds the frozen bucketing inputs. |
| MetricDefinition | name, kind, category, method_default, metric_version, shared_org_wide | — |
| StatTest | — | — |
| Event | event_id, type, experiment_id, user_id, timestamp | See schemas/event.schema.json (authoritative). v1 stores raw prompt/response. |
| MetricResult | test, statistic, p_value, p_value_fdr, effect, ci_low, ci_high, n_per_arm, srm_p, permutations_used, sample_cap_used, window_days, retention_truncated, preliminary | See schemas/metric-result.schema.json (authoritative). |
| AssignRequest | experiment_id, user_id | — |
| AssignResponse | variant, config_version | — |
| IngestAck | accepted, config_version | — |
| ApiKey | scope, key, created_at | — |
| BillingSummary | plan, has_billing_account, billing_configured | — |
| HostedUrl | url | — |
| PlanLimit | plan, retention_days, max_permutations, max_sample_per_arm, monthly_event_allowance | See schemas/plan-limits.schema.json (authoritative). |
The full contract lives at contracts/openapi.yaml in the repository; this page is regenerated from it on every build.