> ## 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.

# API Introduction

> Integrate with User Intuition to manage studies, participants, interviews, and webhooks

## Public Integration API

Supported settings and scoped usage are available through the [public reference and usage endpoints](/api-reference/reference-and-usage).

The User Intuition API allows you to programmatically manage studies, invite participants, access interview recordings and transcripts, generate reports, field panels, and set up webhooks to receive interview data.

Building an autonomous workflow? Start with [Build a research agent](/api-reference/agents) for the review points, safe retry rules, and an evaluation recipe.

For bulk interview evidence, use [interview exports](/api-reference/interview-exports) to request a private CSV or JSONL file by page.

For an agent-friendly study-design flow, create a study draft and call `POST /api/public/v1/studies/{study_id}/customize-plan` once per conversation turn. The default `decisions: "human"` returns structured `questions[]` for the caller to relay. Use `decisions: "agent"` only when the researcher delegates ordinary design choices; report the returned `assumptions[]` and relay any remaining required questions. Put draft-only workflow constraints in `execution_policy`, outside the research `message`. Customization never launches recruitment, and later invitation or paid-launch approval is still required.

For a planning turn that may take longer than the client timeout, use `POST /api/public/v1/studies/{study_id}/customize-plan/jobs`. It returns `202` and a durable `job_id`; poll `GET /api/public/v1/studies/{study_id}/customize-plan/jobs/{job_id}` for the same structured response in `result`. Only one planning turn may run for a study at a time. A failed job is not replayed automatically because a conversation turn may have changed the saved study; inspect that state before explicitly submitting another turn. Upload a native concept image with the synchronous endpoint first, then use the async endpoint for later text turns.

<Card title="OpenAPI Specification" icon="file-code" href="/api-reference/openapi.json">
  View the complete OpenAPI specification
</Card>

The public OpenAPI document is also available from the API host at `https://api.userintuition.ai/openapi.json` and `https://api.userintuition.ai/.well-known/openapi.json`. Both production URLs list public integration endpoints only.

See the [API changelog](/api-reference/changelog) for contract changes and the [versioning and deprecation policy](/api-reference/versioning-and-deprecation) before migrating an integration.

Review the public [Security & Trust center](https://www.userintuition.ai/security/) for current compliance status, data protection, retention, and incident-response details. Interview detail reads can request `redact_pii=true` to mask common structured identifiers and omit direct identity and recording links; this is pattern masking, so applications handling sensitive interviews should still apply their own review controls.

For current availability checks of the API and MCP server, see the [service status page](https://status.userintuition.ai/).

## Safe retries for creating resources

Send a unique `Idempotency-Key` header when creating a study, participant batch, feasibility request, or webhook, uploading a concept image, customizing a study plan, generating a report, sending a participant reward, or launching a paid panel. The combined create-study-with-participants operation accepts it too. If a request times out, retry with **the same key and identical input**. A completed operation returns its original response without repeating the write. Use a new key for a new operation or changed input.

```http theme={null}
Idempotency-Key: 97127ee4-65c2-4978-8f8f-4a19dd19812d
```

Keys are scoped to the authenticated user, organization, and operation. They contain 1–255 visible ASCII characters without spaces. Reusing a key with different input returns `409 idempotency_key_reused`. Completed results can be replayed for 30 days; after that, treat the key as new. If the first request is still running or its result is uncertain, the API returns `409 idempotency_result_pending`; retrieve the current resource before deciding what to do. An unresolved pending operation remains held until reconciled. Calls without a key retain ordinary behavior and cannot be safely replayed after an uncertain timeout.

A changed request that reuses a key did not start; use a new key. A failed read-only check, such as a missing or inaccessible study before creating participants, also does not start the operation, so the same key can be retried after the prerequisite is fixed.

Participant batch creation and report generation return `202` with a durable `job_id`. Poll `GET /api/public/v1/participants/jobs/{job_id}` or `GET /api/public/v1/studies/{study_id}/report/jobs/{job_id}` until `status` is `succeeded`, then follow `result_url`. Failed jobs return a safe summary; contact support with the job ID when a retry has exhausted. A report also emits `report.ready` when persisted. Use `GET /api/public/v1/studies/{study_id}/fielding-progress` for current completions, target, quality counts, and a rate-based finish estimate when enough data exists.

<Card title="Runnable developer examples" icon="code" href="/api-reference/developer-examples">
  Conduct a study, retrieve the four report sections, and search existing evidence. Start with fictional fixtures that require no account or spending.
</Card>

## Base URL

All API requests should be made to:

```
https://api.userintuition.ai
```

## Authentication

All endpoints require Bearer token authentication. You can authenticate with either an **API key** or a **JWT token**.

```bash theme={null}
Authorization: Bearer <your_api_key_or_jwt_token>
```

### API keys (recommended)

API keys are long-lived credentials ideal for server-to-server integrations and MCP clients. Ordinary users' keys are scoped to their organization. They start with the prefix `ui_sk_`.

Users with the platform role `users.role = admin` can read research across organizations. They can [list organization IDs and select one](/api-reference/platform-admins) for scoped operations. An admin's API key still obeys its own scopes and spend cap.

New keys default to `read`. Add `write` to create or change research. Paid panel launches require `panel:launch`, and participant rewards require `rewards:send`, in each case alongside `write` and a positive lifetime USD spend cap. The cap counts reserved and completed operations; an uncertain operation remains reserved until reconciled. Existing keys retain broad public API scopes and may have no cap, so rotate them to adopt the new controls. API keys use the versioned public API and listed catalog reads; dashboard and billing routes require a dashboard session.

An API key can launch a one-time paid panel after receiving an estimate. Recurring panels are created from a dashboard session because later cycles can be repriced beyond a key's one-cycle estimate.

Use the versioned public interview and report endpoints with an API key. The legacy dashboard endpoints that return raw interview messages or embedded call records require a dashboard session token.

Create and manage your keys from the **Manage Account** pane in the dashboard — no API call required to get started.

<Steps>
  <Step title="Open Manage Account">
    Sign in to the [User Intuition Dashboard](https://app.userintuition.ai), click your avatar in the bottom-left corner of the sidebar, then select **Manage Account**.
  </Step>

  <Step title="Go to the API Keys tab">
    In the account management dialog, click **API Keys** in the sidebar.
  </Step>

  <Step title="Create a key">
    Enter a descriptive name, choose scopes, set a lifetime USD cap if selecting a paid scope, then click **Create Key**. The new key appears in a banner at the top of the page.
  </Step>

  <Step title="Copy the key immediately">
    Click **Copy Key** to copy it to your clipboard. The full key is only shown **once** — after you dismiss the banner or navigate away, only the key prefix remains visible.
  </Step>

  <Step title="Use the key">
    Pass the key as a Bearer token in the `Authorization` header:

    ```bash theme={null}
    Authorization: Bearer ui_sk_aBcDeFgHiJkLmNoPqRs...
    ```
  </Step>
</Steps>

To revoke a key, return to the **API Keys** tab and click the trash icon next to it. Revoked keys stop working immediately and cannot be restored.

<Warning>
  The raw API key is only shown once at creation. If you lose it, revoke the old key and create a new one.
</Warning>

<Note>
  See [Account settings → API keys](/resources/account-settings#api-keys) for the full UI walkthrough.
</Note>

### JWT tokens

JWT tokens are short-lived tokens issued by the dashboard. They are useful for quick testing.

<Steps>
  <Step title="Sign in to your account">
    Sign in to your [User Intuition Dashboard](https://app.userintuition.ai) if you haven't already.
  </Step>

  <Step title="Open your profile">
    Click on your profile in the bottom-left corner of the sidebar. This will show your name and company.
  </Step>

  <Step title="Select View JWT Token">
    Select **"View JWT Token"** from the dropdown menu (it has a key icon).
  </Step>

  <Step title="Copy your token">
    A dialog will appear displaying your JWT token. Click the **"Copy Token"** button to copy the token to your clipboard.
  </Step>

  <Step title="Confirmation">
    You'll see a confirmation message when the token has been successfully copied.
  </Step>
</Steps>

<Warning>
  Keep your JWT token secure and do not share it with others. This token provides authenticated access to your account.
</Warning>

## Available Resources

<CardGroup cols={2}>
  <Card title="Studies" icon="robot" href="/api-reference/public-studies/list-studies">
    Create and manage your studies, screeners, and interview configuration.
  </Card>

  <Card title="Interviews" icon="phone" href="/api-reference/public-interviews/list-interviews">
    Access interview records, transcripts, recordings, and analysis data.
  </Card>

  <Card title="Participants" icon="envelope" href="/api-reference/public-participants/create-participants">
    Invite participants, send rewards, and track their status.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/api-reference/webhooks/overview">
    Receive interview data at your own endpoint as soon as an interview completes.
  </Card>
</CardGroup>

## Response Format

All responses are returned in JSON format. Successful list responses include the resource collection plus pagination information (the collection key matches the resource, e.g. `studies`, `participants`, `interviews`):

```json theme={null}
{
  "studies": [...],
  "total_count": 100,
  "page": 1,
  "page_size": 20
}
```

## Error Handling

The API uses standard HTTP status codes:

| Status Code | Description |
| - | - |
| `200` | Success |
| `201` | Created |
| `400` | Bad Request - Invalid input |
| `401` | Unauthorized - Invalid or missing API key or session token |
| `403` | Forbidden - The credential cannot access this resource |
| `404` | Not Found |
| `409` | Conflict - The resource is not in the required state |
| `422` | Validation error |
| `429` | Too Many Requests |
| `500` | Internal Server Error |

Every public API JSON error includes an `error` object and an `X-Request-ID` response header. The `request_id` in the body matches that header. The existing `detail` field remains for clients that already use it; its shape can be a string, list, or object.

```json theme={null}
{
  "detail": {
    "code": "stale_panel_estimate",
    "message": "The estimate expired or its study, launch inputs, balance, or price changed.",
    "recovery_action": "estimate_panel"
  },
  "error": {
    "code": "stale_panel_estimate",
    "message": "The estimate expired or its study, launch inputs, balance, or price changed.",
    "field": null,
    "request_id": "74c5e6ec-9b78-4df1-97ce-bd12c952ca5a",
    "outcome": "not_started",
    "recovery_action": "estimate_panel",
    "docs_url": "https://docs.userintuition.ai/api-reference/introduction"
  }
}
```

For a write with `outcome: "unknown"`, retrieve the current resource state before retrying. `field` identifies the first invalid field when validation fails. Include the request ID when contacting support; do not include credentials.

An error with `outcome: "not_started"` means the request was rejected before that operation changed state. For example, a stale panel estimate or an invalid pause, resume, or stop transition is rejected before launch or fielding changes begin. Other conflicts can still report `unknown`; retrieve the resource before retrying those writes.

| Situation | `outcome` | Recovery |
| - | - | - |
| Input or rate-limit rejection before work begins | `not_started` | Correct input or wait for `Retry-After` |
| A conflict checked before a write | `not_started` | Follow `recovery_action` |
| A write whose result may have changed state | `unknown` | Retrieve current state before retrying |
| A failed read | `failed` | Retry the read |

Use the returned `outcome` and `recovery_action`, not the HTTP status alone, to decide whether a write is safe to repeat.

## Report freshness and historical search

`is_stale: true` means the saved report no longer matches its current inputs. Those inputs include interview evidence, study settings, and report generation settings. Therefore `stale_reason: "inputs_changed"` can appear with `new_interviews_since: 0`; regenerate the report to use the current settings.

Search documents indexed before fieldwork dates were introduced may have `research_period: null`. Date filters exclude undated documents. Older reports with a saved interview evidence snapshot can be reindexed to restore their fieldwork dates; reports without that snapshot must be regenerated before date-filtered search can include them.

## Rate Limiting

API requests are rate limited to ensure fair usage. The default budget is 120 requests per 60 seconds per authenticated user; deployed configuration can change it. Successful responses include `RateLimit-Policy` and `RateLimit` headers showing the active limit, remaining requests, and reset time. A `429 Too Many Requests` response also includes `Retry-After`. Wait for the indicated delay before retrying a read. For a write, check current state before retrying. If the limiter is unavailable, requests continue without rate headers.

## Support

For API support, contact [support@userintuition.ai](mailto:support@userintuition.ai).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.