Skip to main content
A study is a research configuration: the questions, target audience, and settings for a set of interviews. Each study has a public interview link that you send to respondents.

GET /v1/studies

List all active studies for your project. Returns studies with their current usage, whether they’re accepting new responses, and a summary of each study’s Study Manager state (ledger_summary) so you can tell at a glance which study has moved.

Request

string
required
Bearer token. See Authentication.
string
active (default), paused, concluded, or all. Filters on the stored status; a stale or limit-reached study is active.
integer
Number of studies to return. Default 20, max 100.
string
Cursor for pagination. Pass the id of the last study from the previous page.
ledger_summary is null for a study whose Study Manager has not saved yet. See Ledger summary for the fields. If a summary query fails on our side, the affected studies come back with ledger_summary: null and the list still succeeds.
Cache this response for a few minutes. Study capacity doesn’t change often, and caching avoids unnecessary API calls.

GET /v1/studies/:id

Retrieve a single study with full details: what it set out to learn, who is interviewed, what the product is, the questions with their interviewer notes, and the interview count. Add expand=ledger to embed the study’s ledger in the same response.

Request

string
required
Bearer token. See Authentication.
string
required
Study ID (UUID).
string
ledger embeds the study’s current ledger as ledger: the same object GET /v1/studies/:id/ledger returns, active items only, or null before the Study Manager’s first save (not a 404). Without expand, the response has no ledger key. Any other value returns 400.
Returns 404 if the study doesn’t exist or doesn’t belong to your project. Returns 400 with code "invalid_parameter" and param "expand" when expand is anything but ledger.

Study object

string
Study ID (UUID).
string
"study"
string
Display name.
string
"active", "paused", or "concluded": the stored lifecycle, the one a person drives. A study is created active. Pausing and concluding stop the interview link admitting respondents; interviews already in progress finish, and the Study Manager still reviews them. Every move is a status_changed event on the study’s timeline with who made it.
Public URL for respondents. Append ?reference_id=your_user_id to track who completes the interview.
boolean
true exactly when state.value is "active" or "stale": the study is active and no limit has been reached. A paused or concluded study is never accepting, even within its limits.
object
The one displayed state: the stored status folded with the two things that stop or quiet a study without anyone touching it, a limit reached and silence. Computed on read.
string[]
Language codes the study supports (e.g. ["en", "es"]).
object
string
ISO 8601 timestamp.
object
How the study’s completed interviews were graded. Every completed, non-test, non-deleted interview is scored once it is processed (or by hand on the Conversations page) and counts in exactly one of the four counts. A low ratio says the study’s setup is not getting usable conversations (questions, audience, length), not that respondents think anything.

Ledger summary (list only)

Each item of GET /v1/studies carries ledger_summary: the study’s Study Manager state at a glance. The Study Manager is the agent that reads every quality interview and keeps the study’s ledger. The summary is null until the agent has saved its first version, so a study with no ledger is visibly a study with no ledger, never a quiet one. This is a summary, not the ledger: phase is the value alone, and the full object is only on the detail with expand=ledger.
object | null

Detail-only fields

These fields are only included in GET /v1/studies/:id responses:
string | null
What the person who concluded the study wrote: what it settled and what is left open. null when the study was concluded without notes, and when it was never concluded. Written only by the conclude move (uj studies conclude <id> --notes "…", or notes on studies_set_status with to: "concluded"), where a blank note clears it; a reopened study keeps its last notes until it is concluded again. The same text is on the status_changed event as detail.notes.
string | null
The research objective for this study.
string | null
The product being researched.
string | null
What the product is and does, as the interviewer and the Study Manager read it.
string | null
"existing_user" or "discovery".
string | null
Who is being interviewed, in the study owner’s words.
object[]
The interview questions.
integer
Total number of completed interviews for this study.
object | null
Interactive prototype the participant uses during the interview, or null when the study has none. See Interactive prototype.
object | null
Present only with expand=ledger. The study’s current ledger, the same study ledger object as GET /v1/studies/:id/ledger with active items only, or null before the Study Manager’s first save. Unlike the ledger endpoint, a missing ledger is not a 404 here: the study detail is still returned.

Interactive prototype

A study can embed a live web prototype in the interview instead of static screenshots. The switch is per study: prototype_config is null (off) or an object, set through the studies_config_update MCP tool or uj studies config set <id> --file config.json.
  • baseUrl must be https (http is allowed only for localhost). The prototype publishes its valid { screen, scenario } pairs at GET {baseUrl}/api/states.
  • description (max 240 characters) is what the interviewer agent reads about the start state.
  • prototype is the prototype’s id: every message the prototype posts carries it as source, and the participant page accepts no other. Copy it from GET {baseUrl}/api/states.
  • screens (optional, up to 12 of { id, description }) tells the agent what each screen of the prototype is and what the participant can do there, so it understands its live context notes. Copy the screens array from GET {baseUrl}/api/states.
  • flows (optional, up to 8 of { task, steps }) tells the agent how common tasks are done, so it can guide a stuck participant. Copy it from GET {baseUrl}/api/states.
  • events (optional, up to 64 of { token, meaning, use }) tells the agent what each of the prototype’s context notes means and how to act on it. Copy it from GET {baseUrl}/api/states.
  • The agent receives exactly two stimulus ids for the prototype: PROTOTYPE_START shows it, PROTOTYPE_END hides it. Question notes must say when to call them, for example “Call PROTOTYPE_START now and keep it visible until the last question.”
  • While the prototype is visible, the participant’s actions are summarised to the agent as short context notes and recorded in the interview’s session replay. The prototype writes those notes itself; see Prototype messages.

Prototype messages

The prototype posts one message per interaction to window.parent:
  • source must equal prototype_config.prototype; type is the prototype’s own event name; ts, seq and sessionId identify the message.
  • note (max 280 characters) is what the agent reads. events in the study config explains every note.
  • delivery: now (default) sends the note; activity sends nothing and only shows the participant is busy, so the agent is not told they are idle. A now message without a note reaches the agent as event=<type>.
  • merge: a key; a newer note with the same key replaces the pending one, e.g. typing sends typed=12 then typed=40 and the agent receives typed=40.
  • state: values that open every note, on=<screen> first (null removes a key).
  • Notes are batched (1.5 s), repeats collapse to x<n>, and the agent receives at most 12 updates a minute. After 20 seconds without any message the agent is told idle=<s>.