> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userintuition.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Public API request examples

> Copyable requests and exact inputs for every public integration API operation.

These examples use the production API. Replace the sample IDs with IDs returned by your own account. Set your API key once before running the commands:

```bash theme={null}
export API_KEY='ui_sk_your_key'
export STUDY_ID='study_id_from_create_response'
export PARTICIPANT_ID='participant_id_from_create_response'
export INTERVIEW_ID='interview_id_from_list_response'
export REQUEST_ID='request_id_from_feasibility_response'
```

All requests need `Authorization: Bearer $API_KEY`. Requests with JSON bodies also need `Content-Type: application/json`. A `422` response means a field or value failed request validation; the response's `detail` identifies it. Path IDs go in the URL, not the JSON body, unless a schema explicitly includes an ID field.

## Studies

### List studies · `GET /api/public/v1/studies/`

```bash theme={null}
curl -G 'https://api.userintuition.ai/api/public/v1/studies/' \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode 'page=1' \
  --data-urlencode 'page_size=20' \
  --data-urlencode 'name=Pricing'
```

`page` starts at 1; `page_size` can be 1–1000 and defaults to 100. `name` filters by study name and is optional. Omit the query parameters to list the first page with defaults. The response has `studies`, `total_count`, `page`, and `page_size`; use a study's `id` for later requests. Use get-by-ID to retrieve its full plan and screeners.

### Create a study · `POST /api/public/v1/studies/`

This example creates a configured BYOP chat study about a recent appliance purchase. `study_plan.objectives` and `study_plan.conversation_flow` are both required when `study_plan` is present. `expected_duration_seconds` is a planned maximum in seconds and must be at least 300; `300` means five minutes. The custom screener disqualifies respondents who choose “No.”

```bash theme={null}
curl -X POST 'https://api.userintuition.ai/api/public/v1/studies/' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Recent appliance purchases",
    "study_type": "in-depth-interview",
    "recruiting_method": "byop",
    "interview_format": "chat",
    "voice": "male",
    "language": "en",
    "expected_duration_seconds": 300,
    "study_plan": {
      "objectives": "Understand what triggered one recent blender or microwave purchase, which alternatives were considered, and how price and reliability affected the choice.",
      "conversation_flow": "Ask for the participant’s purchase story. Explore the need that triggered it, the closest alternative, the price-versus-reliability tradeoff, and satisfaction after using the appliance.",
      "background": "Exploratory research into household appliance purchase decisions."
    },
    "screener_questions": [{
      "text": "Have you bought a blender or microwave in the past year?",
      "type": "single_select",
      "options": [
        {"text": "Yes", "disqualify": false},
        {"text": "No", "disqualify": true}
      ]
    }]
  }'
```

Valid `study_type` values are `in-depth-interview`, `concept-test`, and `prototype-test`. Valid `recruiting_method` values are `byop` and `panel`; if omitted, the study defaults to BYOP. Valid `interview_format` values are `chat`, `video`, and `voice`; prototype tests cannot use `chat`. `voice` is `male` (Elliot) or `female` (Clara). Use a supported two-letter language code such as `en`, or `auto`. The name has a 40-character limit. `screener_questions` can also use `multi_select` or `text_input`; multi-select options must each set `selection_rule` to `must_select`, `may_select`, or `reject`.

Save the returned `id` as `STUDY_ID`. Check `provisioning_status`: `draft` means `missing_requirements` lists what to add; `ready` means configured but not yet provisioned; `provisioned` means interviews can run. `study_link` is the participant interview URL when available, and `dashboard_url` is the management URL. Creation does **not** accept `byop_config`; set BYOP incentives with PATCH after creation.

### Create a study and invite participants · `POST /api/public/v1/studies/create-with-participants`

Pass a complete BYOP study plus 1–100 participants. Emails must be unique, ignoring case. `silent: true` creates an invitation without sending its invitation email. This endpoint requires the new study to be provisioned before invitations are created; if it cannot be provisioned or an invitation fails, the new study is rolled back.

```bash theme={null}
curl -X POST 'https://api.userintuition.ai/api/public/v1/studies/create-with-participants' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "study": {
      "name": "AI research tool shortlist",
      "study_type": "in-depth-interview",
      "recruiting_method": "byop",
      "interview_format": "voice",
      "voice": "male",
      "language": "en",
      "expected_duration_seconds": 1080,
      "study_plan": {
        "objectives": "Understand what makes startup CEOs shortlist an AI research tool and what proof they need before considering one seriously.",
        "conversation_flow": "Ask about a recent customer-research decision, the trigger to look for an AI tool, alternatives considered, trust concerns, and proof needed to shortlist a provider."
      }
    },
    "participants": [
      {"email": "alex@example.com"},
      {"email": "sam@example.com", "silent": true}
    ]
  }'
```

The response contains `study` and `participants`. Use `study.id` for study operations and each `participants[].id` for participant operations. Neither `study.byop_config` nor a top-level `byop_config` is accepted.

### Get a study · `GET /api/public/v1/studies/{study_id}`

```bash theme={null}
curl "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID" \
  -H "Authorization: Bearer $API_KEY"
```

Use the full response to inspect `study_plan`, `screener_questions`, `targeting_attributes`, `provisioning_status`, `missing_requirements`, and the participant `study_link`.

### Customize the study plan · `POST /api/public/v1/studies/{study_id}/customize-plan`

Send one user turn at a time. The server stores the conversation ID on the study; the next call only needs a new `message`. Relay a returned `response_type: "question"` to the person designing the study and pass their answer in the next request. A `response_type: "study_plan"` means the generated plan was saved.

```bash theme={null}
curl -X POST "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/customize-plan" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "message": "We want to understand how households choose a blender or microwave. Ask about one recent purchase, what triggered it, the closest alternative, and how they weighed price against reliability."
  }'
```

`message` must be 1–20,000 characters. To attach a concept image to the same turn, add `concept_image` with `data_base64` (base64 image bytes, not a data URL), `filename`, `content_type` (`image/png`, `image/jpeg`, `image/gif`, or `image/webp`), and a participant-facing `label`. The decoded file must be at most 10 MB. For example, the optional object is `{"data_base64":"<base64 bytes>","filename":"checkout.png","content_type":"image/png","label":"Checkout screen"}`.

### Change only selected study fields · `PATCH /api/public/v1/studies/{study_id}`

Use PATCH for a partial change. This example turns on a $25 BYOP incentive and automatic rewards. `byop_config` is accepted on update, but not on creation; `incentive_amount` must be $5–\$500. Only provided fields change.

```bash theme={null}
curl -X PATCH "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "byop_config": {
      "incentive_amount": 25,
      "is_incentives_enabled": true,
      "auto_send_incentives": true
    }
  }'
```

For a draft missing interviewer settings, a PATCH such as `{"voice":"female","language":"en"}` supplies those fields without clearing its existing plan. For a fielding Panel study, first pause or stop it; an edit otherwise returns `409` with the allowed actions.

### Replace a study · `PUT /api/public/v1/studies/{study_id}`

PUT describes the full desired state; fields you omit are cleared. Fetch the study first, then send every field you want to retain. In particular, include `study_plan`, screeners, and panel targeting attributes if they should stay. This example replaces a simple BYOP study without screeners or incentives.

```bash theme={null}
curl -X PUT "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Updated buyer interviews",
    "study_type": "in-depth-interview",
    "recruiting_method": "byop",
    "interview_format": "voice",
    "voice": "female",
    "language": "en",
    "expected_duration_seconds": 1200,
    "study_plan": {
      "objectives": "Understand subscription buying decisions.",
      "conversation_flow": "Discuss the most recent decision, alternatives, and acceptable prices."
    },
    "screener_questions": []
  }'
```

### Delete, pause, resume, or stop a study

These operations use the path ID and an authorization header; they take **no JSON body**.

```bash theme={null}
curl -X POST "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/pause" -H "Authorization: Bearer $API_KEY"
curl -X POST "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/resume" -H "Authorization: Bearer $API_KEY"
curl -X POST "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/stop" -H "Authorization: Bearer $API_KEY"
curl -X DELETE "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID" -H "Authorization: Bearer $API_KEY"
```

`pause` temporarily blocks new responses and preserves an existing panel; `resume` continues it. `stop` ends recruitment and settles the panel hold. `DELETE` deletes the study. Run only the operation you intend; the four commands above are alternatives, not a sequence.

## Panels, targeting, and feasibility

### Find panel qualifications · `GET /api/public/v1/targeting-attributes/`

```bash theme={null}
curl -G 'https://api.userintuition.ai/api/public/v1/targeting-attributes/' \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode 'name=Gender'
```

`name` is an optional case-insensitive search. `category` is an optional case-insensitive exact category filter; omit both to list the catalog. Use returned `qualification_id` and `options[].option_id` values in study `targeting_attributes` and panel `option_targets`. Do not invent these IDs.

### Find supported countries · `GET /api/public/v1/panel-countries/`

```bash theme={null}
curl -G 'https://api.userintuition.ai/api/public/v1/panel-countries/' \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode 'language=EN'
```

Pass **either** `language=EN` to list countries supporting that language **or** `country=US` to inspect one country's `language_options`; passing both returns `400`. Omit both to list all. Panel requests require a supported `country_code`, and the country must support the study's interview language.

### Estimate or launch a panel for an existing study · `POST /api/public/v1/studies/{study_id}/launch-panel`

First create or update a **Panel** study (`recruiting_method: "panel"`). This request reserves 8 of 20 completed interviews for option ID 1 of qualification ID 2; the remaining 12 remain open to other eligible options. Replace the catalog IDs with IDs returned by the targeting endpoint and configure qualification 2 on the study before launch.

```bash theme={null}
curl -X POST "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/launch-panel" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "target": 20,
    "incident_rate": 25,
    "country_code": "US",
    "frequency": "one-time",
    "dry_run": true,
    "targeting_attributes": [{
      "qualification_id": 2,
      "option_targets": [{"option_id": 1, "target": 8}]
    }]
  }'
```

`target` is a positive whole number of completed interviews. `incident_rate` is a percentage from 0–100; `25` means 25%, **not** `0.25`. Rates below 10% need a feasibility request before direct panel launch. `frequency` is `one-time`, `weekly`, `monthly`, or `quarterly`. `dry_run: true` returns a cost and timeline estimate without fielding; review `estimated_total_cost_usd` and `estimated_timeline_hours`. Set `dry_run: false` only when ready to field a provisioned study and pay for the panel. `targeting_attributes` is optional; omit it for an untargeted panel.

### Create a study and estimate or launch its panel · `POST /api/public/v1/studies/create-and-launch-panel`

This is a single request with separate `study` and `panel` objects. For a dry run, it estimates without creating a study. For a real launch, the study must contain enough settings to provision its interviewer; the example supplies name, plan, voice, and language. This example targets the C-level/owner option for the job-title qualification; verify its IDs in the targeting catalog before sending the request. The backend forces Panel recruitment regardless of the optional `study.recruiting_method`.

```bash theme={null}
curl -X POST 'https://api.userintuition.ai/api/public/v1/studies/create-and-launch-panel' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "study": {
      "name": "Startup CEO AI tool shortlist",
      "study_type": "in-depth-interview",
      "recruiting_method": "panel",
      "interview_format": "voice",
      "voice": "male",
      "language": "en",
      "expected_duration_seconds": 1200,
      "study_plan": {
        "objectives": "Understand what triggers startup CEOs to evaluate AI-powered research tools, how they build a shortlist, and what proof makes a provider credible.",
        "conversation_flow": "Discuss the last important customer-research decision, how the CEO gathered input, why they considered an AI tool, alternatives they compared, trust thresholds, and evidence needed to shortlist one."
      },
      "targeting_attributes": [{
        "qualification_id": 89,
        "allowed_options": [1],
        "disallowed_options": []
      }],
      "screener_questions": [{
        "text": "Are you the founder or CEO of a startup?",
        "type": "single_select",
        "options": [
          {"text": "Yes", "disqualify": false},
          {"text": "No", "disqualify": true}
        ]
      }]
    },
    "panel": {
      "target": 20,
      "incident_rate": 25,
      "country_code": "US",
      "dry_run": true
    }
  }'
```

The dry-run response has `study: null` and an estimated `panel`. To create and field, change `panel.dry_run` to `false`; the response includes the new study and panel status. `study.byop_config` is not accepted here. In this example, qualification `89` is job title and option `1` is the C-level/owner answer; the custom screener narrows that broader qualification to founders and CEOs. Panel option quotas, if needed, go in `panel.targeting_attributes` as shown above; quotas require at least two eligible options for that qualification.

### Submit a low-incidence or niche audience · `POST /api/public/v1/feasibility-requests/`

```bash theme={null}
curl -X POST 'https://api.userintuition.ai/api/public/v1/feasibility-requests/' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "target_audience": "US startup CEOs who have evaluated AI tools for customer research in the past six months",
    "country_code": ["US"],
    "target": 20,
    "incident_rate": 8.5
  }'
```

`target_audience` is a nonblank description. `country_code` is an optional **array** of supported two-letter codes; omit it for no country restriction. `target` must be positive. `incident_rate` is percentage points, so `8.5` means 8.5%. Add `study_id` only if you already have a study and want to attach this request to it. The response's `id` is the feasibility request ID, and `status` starts at `RECEIVED`.

### List or get feasibility requests

```bash theme={null}
curl 'https://api.userintuition.ai/api/public/v1/feasibility-requests/' -H "Authorization: Bearer $API_KEY"
curl "https://api.userintuition.ai/api/public/v1/feasibility-requests/$REQUEST_ID" -H "Authorization: Bearer $API_KEY"
```

The list is an array of your account's requests, newest first. The get request takes the `id` returned by submit or list and returns its current `status` (`RECEIVED` or `RESPONDED`) and any available estimate. Neither GET takes a JSON body.

## Participants

### List participants · `GET /api/public/v1/participants/`

```bash theme={null}
curl -G 'https://api.userintuition.ai/api/public/v1/participants/' \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode 'study_id=study_id_from_create_response' \
  --data-urlencode 'page=1' \
  --data-urlencode 'page_size=20'
```

Replace `study_id_from_create_response` with the actual study ID. `study_id` and `email` are optional filters. `page` starts at 1; `page_size` can be 1–100 and defaults to 10. The response has `participants`, `total_count`, `page`, and `page_size`. These are your own invited participants; Panel respondents are not synthesized into participant records.

### Invite participants · `POST /api/public/v1/participants/`

Use a provisioned BYOP study. Send 1–100 distinct emails. `silent: true` creates the participant without sending an invitation email. The response is an array of created participants; keep each `id` for get, update, or reward operations.

```bash theme={null}
curl -X POST 'https://api.userintuition.ai/api/public/v1/participants/' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "study_id": "study_id_from_create_response",
    "participants": [
      {"email": "alex@example.com", "silent": false},
      {"email": "sam@example.com", "silent": true}
    ]
  }'
```

### Get or change a participant

```bash theme={null}
curl "https://api.userintuition.ai/api/public/v1/participants/$PARTICIPANT_ID" \
  -H "Authorization: Bearer $API_KEY"

curl -X PUT "https://api.userintuition.ai/api/public/v1/participants/$PARTICIPANT_ID" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"email":"alex.new@example.com"}'
```

The GET has no body. The PUT accepts `email` as its only JSON field; the participant ID comes from the URL. The response shows the current email, invitation timestamps, and reward state.

### Send a BYOP reward · `POST /api/public/v1/participants/{participant_id}/reward`

```bash theme={null}
curl -X POST "https://api.userintuition.ai/api/public/v1/participants/$PARTICIPANT_ID/reward" \
  -H "Authorization: Bearer $API_KEY"
```

This operation takes **no JSON body**. It sends the study's configured incentive to this BYOP participant and returns `202 Accepted` when queued. Set the incentive with study PATCH first; check `reward_sent` and `reward_sent_at` on the participant response. This is a payment action, so select the intended participant ID carefully.

## Interviews and reports

### List interviews · `GET /api/public/v1/interviews/`

```bash theme={null}
curl -G 'https://api.userintuition.ai/api/public/v1/interviews/' \
  -H "Authorization: Bearer $API_KEY" \
  --data-urlencode 'study_id=study_id_from_create_response' \
  --data-urlencode 'status=completed' \
  --data-urlencode 'quality=Good' \
  --data-urlencode 'quality=Excellent' \
  --data-urlencode 'page=1' \
  --data-urlencode 'page_size=20'
```

Replace the study ID. `study_id`, `status`, and `quality` are optional filters; repeat `quality` for more than one label. Quality labels are `Excellent`, `Good`, `Fair`, and `Poor`. `page` starts at 1; `page_size` can be 1–100 and defaults to 10. The response has `interviews`, `total_count`, `page`, and `page_size`; use an interview's `id` for get or delete.

### Get or delete an interview

```bash theme={null}
curl "https://api.userintuition.ai/api/public/v1/interviews/$INTERVIEW_ID" \
  -H "Authorization: Bearer $API_KEY"

curl -X DELETE "https://api.userintuition.ai/api/public/v1/interviews/$INTERVIEW_ID" \
  -H "Authorization: Bearer $API_KEY"
```

GET returns the full public interview, including available messages, quality, recording URLs, and screener responses. DELETE soft-deletes it and returns `204 No Content`. Both use the path ID and take no JSON body; run DELETE only if you intend to remove that interview.

### Generate or fetch a study report

```bash theme={null}
curl -X POST "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/report" \
  -H "Authorization: Bearer $API_KEY"

curl "https://api.userintuition.ai/api/public/v1/studies/$STUDY_ID/report" \
  -H "Authorization: Bearer $API_KEY"
```

POST generates a report from the study's interviews; GET retrieves the saved report. Both use the study ID in the URL and take no JSON body. The report response includes its available report content and references; generate after interviews have completed.

## Webhooks

### Register · `POST /api/public/v1/webhooks/`

```bash theme={null}
curl -X POST 'https://api.userintuition.ai/api/public/v1/webhooks/' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"hook_url":"https://your-company.example/webhooks/user-intuition"}'
```

`hook_url` is the HTTPS endpoint on your server that will receive completed-interview POSTs. It is **account-wide**; do not pass `study_id`. The response includes `signing_secret`, shown once. Store it and verify `X-UI-Signature` against the raw request body as described in [Webhooks](/api-reference/webhooks/overview). Respond with `2xx` quickly; failed deliveries are not retried.

### Unregister · `DELETE /api/public/v1/webhooks/`

```bash theme={null}
curl -X DELETE 'https://api.userintuition.ai/api/public/v1/webhooks/' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"hook_url":"https://your-company.example/webhooks/user-intuition"}'
```

Pass the **same** `hook_url` used for registration. This DELETE is one of the operations that does take a JSON body; it does not use a webhook ID in the URL.
