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

# Listen Labs API

> Create, launch, and retrieve data from Listen Labs studies programmatically

The Listen Labs API lets you run studies entirely from code: define a study guide as JSON, create a draft, launch it to get a self-recruit link you can distribute to participants, and pull responses back out once interviews come in.

## Base URL

```
https://listenlabs.ai
```

## Authentication

All endpoints authenticate with an API key passed in the `x-api-key` header. The key is scoped to a single organization — studies are created in, and wallets are listed for, that organization.

```bash theme={null}
curl 'https://listenlabs.ai/api/public/v1/wallets' \
  -H 'x-api-key: <api_key>'
```

Admins and Supervisors can create API keys from the **Developer** section of their account page on Listen. See [Get API Access](/get-api-access) for details.

## Workflow

<Steps>
  <Step title="Create a draft study">
    `POST /api/public/v1/studies/create` with a title and a [study guide](/api-v2/study-guide). The guide is validated up front; if it passes, you get back a draft study's `id` and `linkId`. Nothing is visible to participants yet — you can still review or edit the draft in the dashboard.
  </Step>

  <Step title="Pick a wallet (optional)">
    `GET /api/public/v1/wallets` lists the wallets granted to your organization with their recruitment and project credit balances. `walletId` can only be omitted at launch when your organization has exactly one wallet (it's auto-selected). If you have access to more than one, omitting it returns a `400` (`wallet_required`) — you must pass one from this list.
  </Step>

  <Step title="Launch">
    `POST /api/public/v1/studies/{studyId}/launch` publishes the draft and opens its self-recruit link. The response includes `selfRecruitLink` — share it with participants (or plug it into your own recruitment flow). Project responses bill to the launch wallet.
  </Step>

  <Step title="Retrieve responses">
    Once interviews come in, pull them with [Get Responses](/api-v2/list-responses) (`GET /api/public/v1/responses/{linkId}`) and drill into a single transcript with [Get Single Response](/api-v2/get-response). The `linkId` comes back from create/launch, or from [List Studies](/endpoint). The [Data Map](/data-map) shows how these entities join together.
  </Step>
</Steps>

<Card title="Quickstart" icon="bolt" href="/api-v2/quickstart">
  A complete create → launch example you can copy and run.
</Card>

## Endpoints

| Endpoint                                                                     | Description                                      |
| ---------------------------------------------------------------------------- | ------------------------------------------------ |
| [`POST /api/public/v1/studies/create`](/api-v2/create-study)                 | Validate a study guide and create a draft study  |
| [`POST /api/public/v1/studies/{studyId}/launch`](/api-v2/launch-study)       | Publish a draft and return the self-recruit link |
| [`GET /api/public/v1/wallets`](/api-v2/list-wallets)                         | List the organization's wallets with balances    |
| [`GET /api/public/v1/responses/{linkId}`](/api-v2/list-responses)            | List all responses for a study                   |
| [`GET /api/public/v1/responses/{linkId}/{responseId}`](/api-v2/get-response) | Retrieve a single response                       |
| [`GET /api/public/list_surveys`](/endpoint)                                  | List all studies in the organization             |
| [`GET /api/public/studies/{study_id}/questions`](/get-study-questions)       | List all questions for a study                   |

<Warning>
  The unversioned response endpoints — [`GET /api/public/responses/{link_id}`](/get-responses) and
  [`GET /api/public/responses/{link_id}/{response_id}`](/get-single-response) — are deprecated
  starting **August 1, 2026**. Migrate to the versioned `/api/public/v1/responses/...` endpoints
  above before then.
</Warning>

## Errors

Every error response from the `/api/public/v1/*` endpoints shares one JSON envelope:

* `error` — a human-readable message. Useful for logs, but it may change; **don't** branch on it.
* `code` — a stable, machine-readable identifier. **Branch on this.**
* `issues` — present only on `400` schema failures (`code: invalid_request_body`): an array of per-field violations, each with a `path` and `message`.

```json 400 Schema violation theme={null}
{
  "error": "Invalid request body",
  "code": "invalid_request_body",
  "issues": [
    {
      "code": "invalid_type",
      "expected": "string",
      "received": "undefined",
      "path": ["title"],
      "message": "Required"
    }
  ]
}
```

```json 400 Invalid study guide theme={null}
{
  "error": "Invalid study guide: conditional references unknown item externalId 'q2'",
  "code": "invalid_study_guide"
}
```

### Error codes

| Status | Code                       | Meaning                                                                               |
| ------ | -------------------------- | ------------------------------------------------------------------------------------- |
| `400`  | `invalid_json`             | Request body isn't valid JSON.                                                        |
| `400`  | `invalid_request_body`     | Body failed schema validation. See `issues` for per-field details.                    |
| `400`  | `invalid_study_guide`      | The study guide broke a cross-field rule (create only).                               |
| `400`  | `wallet_required`          | The organization has multiple wallets and `walletId` was omitted (launch only).       |
| `400`  | `insufficient_credits`     | The wallet can't fund the launch — insufficient balance or grant limit (launch only). |
| `400`  | `bad_request`              | A query or path parameter is invalid (response endpoints only).                       |
| `401`  | `missing_api_key`          | No `x-api-key` header.                                                                |
| `401`  | `invalid_api_key`          | The API key is invalid.                                                               |
| `403`  | `forbidden`                | The key's user isn't a member of the key's organization.                              |
| `403`  | `launch_permission_denied` | The key's user lacks permission to launch this study.                                 |
| `403`  | `wallet_access_denied`     | No access to the specified wallet.                                                    |
| `404`  | `study_not_found`          | Study not found in the key's organization.                                            |
| `404`  | `response_not_found`       | Response not found in the study (get response only).                                  |
| `409`  | `concurrent_modification`  | The draft was modified concurrently; retry (create only).                             |
| `409`  | `study_busy`               | An update is in flight; retry after a moment (launch only).                           |
| `409`  | `conflict`                 | The publish raced a concurrent edit; refresh and retry (launch only).                 |
| `500`  | `internal_error`           | Internal error. Details are logged server-side, not returned.                         |

<Note>
  Beyond field-level validation, the server enforces cross-field rules on the study guide (screening block placement, `minSelect`/`maxSelect` coupling, unique `externalId`s, reference resolution, `exclusiveOption` placement) and returns violations as `400` responses (`code: invalid_study_guide`). The full list is in the [Study Guide Reference](/api-v2/study-guide#validation-rules).
</Note>
