Skip to main content
POST

Authorizations

Authorization
string
header
required

A Curious API key: curious_sk_… (secret) or curious_pk_… (publishable), live or test environment (curious_sk_test_…). Publishable keys are serve-only and origin-gated; declare and identify require a secret key. A revoked or unknown key is a 401.

Body

application/json
element
string
required

Identifier of the surface being optimized.

Minimum string length: 1
Pattern: \S
user_id
string
required

The caller's identifier for the user.

Minimum string length: 1
Pattern: \S
identifiers
object

Durable identity (email, name, phone); merged into the user.

attributes
object

Durable user state (plan, company_size); merged into the user and used for personalization.

context
object

Situational facts for this decision only (device, page); wins over stored attributes on a key collision.

idempotency_key
string

An opaque key, 1–255 characters, generated before the first attempt and reused on every retry of the same logical request. Same key and same request replays the original decision; same key and a different request is a 409. A UUID is the recommended shape. The key may not contain U+0000 or an unpaired surrogate.

Required string length: 1 - 255
Pattern: ^[^\u0000\uD800-\uDFFF]*$
control

The counterfactual baseline: the content you would serve without Curious. Singular, never an array; required whenever the call creates an experiment. A changed control supersedes the experiment.

arms

Additional starting points beside the control: one entry or a list, each bare content or {content, hypothesis}. Additive and idempotent: an entry the experiment already has is skipped. Entries that duplicate an earlier entry in the same request are skipped with an arm_invalid warning, and so are entries that violate the format or the requirements, or that would exceed the 50-active-arm cap. Two rules are request errors (400): an entry whose content equals the control's, and more than 10 distinct entries after duplicates are dropped — the limit counts distinct contents, so the list itself is not capped here.

rewards

The rewards the experiment optimizes. Shorthand: a name, an object, or a list of either; a bare name means a binary reward with weight 1 and a one-day window.

Minimum string length: 1
constraints
object[]

Guardrails an arm may not breach. Each (name, type, bound, properties) identity may appear once; threshold, threshold_type and window_seconds are its adjustable fields. Changing constraints never supersedes the experiment.

requirements
object

Phrase rules every arm must satisfy. Changing them supersedes the experiment.

instructions
string

Guidance for future generation rounds. Updates in place.

element_type
enum<string> | null

The element's kind. Case-insensitive on input. Null means unset.

Available options:
push_notification,
email_subject,
email_preview,
email_body,
email,
button_cta,
hero,
landing_page,
blog_post,
paywall,
null
format
object

The structural content contract: a single field spec, or an object of named field specs. Omitted on a first call, it is inferred from the control; declared, the control must match it. A changed format supersedes the experiment.

variables
string[]

Names that arm content may reference as {{name|fallback}}, substituted from the user's identifiers and attributes at decision time. Defaults, on creation, to the identifier and attribute keys sent. Updates in place.

Pattern: ^\w+$
parameters
object

Element-content facts fixed for the experiment and reproduced verbatim through {{placeholders}}. Keys match ^\w+$; the namespace is disjoint from variables. Any change supersedes the experiment.

options
object

Serving-policy knobs. assignment, approval and minimum_effect_size update in place; holdout is fixed for the experiment's life and a differing value supersedes it. Every default is resolved when the experiment is created and stored with it, so a later change to a default never alters a live experiment; an omitted key on a later call carries the stored value forward.

Response

The decision (singular form), or the per-item results (batch form). A replayed decision is the original response verbatim plus replayed: true.

content
required

The selected arm's content after {{variable}} substitution.

arm_id
string<uuid>
required
arm_type
enum<string> | null
required
Available options:
control,
variant,
null
decision_id
string<uuid>
required

The id of the decision row this call committed. Repeated serves of the same arm carry different ids.

experiment_id
string<uuid>
required
experiment_status
enum<string>
required

initializing until the first model is minted, then exploring; concluded is terminal.

Available options:
initializing,
exploring,
concluded
warnings
object[]

Present only when non-empty.

Minimum array length: 1
replayed
boolean

Present only when this is the stored response to an earlier request with the same idempotency_key.