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

# Data API

> Read issues, signals, and insights over REST, and update issue status using bearer tokens.

The Lucent Data API is a REST surface for reading Lucent data and updating
issue status from scripts, dashboards, and services.

## Base URL

```text theme={null}
https://app.lucenthq.com
```

All endpoints below are relative to this base URL.

## Authentication

Send a bearer token in the `Authorization` header:

```bash theme={null}
curl -sS https://app.lucenthq.com/api/v1/issues?limit=10 \
  -H "Authorization: Bearer luc_api_..."
```

The Data API accepts API keys and OAuth access tokens:

* API keys that start with `luc_api_`
* OAuth access tokens that start with `luc_oat_`

Legacy static keys with the `luc_mcp_` prefix continue to work.

Read endpoints require `read:lucent`. Updating issue status requires
`write:issues`.

Create API keys in **Organization settings → MCP**. Choose **Allow issue status
updates** when the key needs to call `PATCH /api/v1/issues/{issueId}`.
OAuth clients should follow the [OAuth reference](/mcp/oauth) and request only
the scopes they need.

<Note>
  Browser dashboard sessions do not authenticate the Data API. These endpoints
  are for bearer-token clients and return JSON errors when the token is missing
  or invalid.
</Note>

## Endpoints

| Method  | Path                                                             | Scope          | Query params                | Description                               |
| ------- | ---------------------------------------------------------------- | -------------- | --------------------------- | ----------------------------------------- |
| `GET`   | [`/api/v1/issues`](/api-reference/list-issues)                   | `read:lucent`  | `limit`, `status`, `cursor` | List issues for the token's organization. |
| `GET`   | [`/api/v1/issues/{issueId}`](/api-reference/get-an-issue)        | `read:lucent`  | —                           | Fetch a single issue by UUID.             |
| `PATCH` | [`/api/v1/issues/{issueId}`](/api-reference/update-issue-status) | `write:issues` | —                           | Update an issue's status.                 |
| `GET`   | [`/api/v1/signals`](/api-reference/list-signals)                 | `read:lucent`  | `limit`, `cursor`           | List configured signals and match counts. |
| `GET`   | [`/api/v1/insights`](/api-reference/list-insights)               | `read:lucent`  | `limit`, `cursor`           | List recent AI-generated insights.        |

Every request is scoped to the organization that owns the token. There is no
`orgId` query parameter.

## Limits

| Endpoint           | Default limit | Max limit |
| ------------------ | ------------- | --------- |
| `/api/v1/issues`   | `25`          | `200`     |
| `/api/v1/signals`  | `50`          | `200`     |
| `/api/v1/insights` | `25`          | `100`     |

`limit` must be an integer within the endpoint's range.

List endpoints are ordered by `createdAt` descending, then `id` descending.

## Pagination

List responses include `nextCursor`:

```json theme={null}
{
  "issues": [],
  "nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTAyLTI0VDEwOjMyOjE5LjA2NloiLCJpZCI6Ijg3YjNhNmI2LTVhZjUtNDM4Yi1hMzljLWVmZjE0OGE2OGNjYiJ9"
}
```

If `nextCursor` is not `null`, pass it back as the `cursor` query parameter to
fetch the next page:

```http theme={null}
GET /api/v1/issues?limit=25&cursor=eyJjcmVhdGVkQXQiOiIyMDI2...
Authorization: Bearer luc_api_...
```

The cursor is opaque. Do not parse or construct it yourself.

## Rate limits

| Request type | Limit                                             |
| ------------ | ------------------------------------------------- |
| Reads        | 300 requests per minute per token or OAuth client |
| Writes       | 60 requests per minute per token or OAuth client  |

Rate-limited responses return `429` and include `Retry-After`,
`X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers.

## Errors

All error responses are JSON and include `Cache-Control: no-store`.

| Status | Example body                                                                         | Meaning                                                        |
| ------ | ------------------------------------------------------------------------------------ | -------------------------------------------------------------- |
| `400`  | `{"error":"limit must be an integer between 1 and 200"}`                             | Invalid query parameter.                                       |
| `400`  | `{"error":"Request body must be valid JSON"}`                                        | Invalid JSON body for a write request.                         |
| `400`  | `{"error":"status must be one of: unresolved, ticket_created, transient, resolved"}` | Invalid issue status.                                          |
| `401`  | `{"error":"Missing or invalid bearer token"}`                                        | Missing, malformed, revoked, or unknown bearer token.          |
| `403`  | `{"error":"Missing required scope: write:issues"}`                                   | The token is valid but lacks the required scope.               |
| `404`  | `{"error":"Issue not found"}`                                                        | The requested issue was not found in the token's organization. |
| `429`  | `{"error":"Rate limit exceeded"}`                                                    | The token or OAuth client exceeded its per-minute limit.       |

`401` responses include:

```http theme={null}
WWW-Authenticate: Bearer scope="read:lucent"
```

For write endpoints, the challenge scope is `write:issues`.
