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

# Endpoints

> Reference for the five thread endpoints that make up the public API.

<Warning>
  **Deprecation:** The Endgame REST API is being deprecated on **October 1,
  2026**. For automated processes and integrations, we recommend the [Endgame
  MCP server](/features/mcp-server) instead.
</Warning>

The public API is a small resource-oriented CRUD surface for **threads**
\-- the conversational units that power Endgame Chat. Every endpoint is
rooted at `/api/v1`, authenticates with a Bearer `eak_*` key, and
exchanges JSON.

A typical workflow: **create** a thread with a prompt, **poll** it by ID
until the assistant's response finishes, and optionally **list**,
**rename**, or **delete** it.

| Method | Path | Purpose |
| - | - | - |
| `POST` | `/threads` | [Create a thread](#create-a-thread) |
| `GET` | `/threads/{id}` | [Get a thread](#get-a-thread) |
| `GET` | `/threads` | [List threads](#list-threads) |
| `PATCH` | `/threads/{id}` | [Rename a thread](#rename-a-thread) |
| `DELETE` | `/threads/{id}` | [Delete a thread](#delete-a-thread) |

***

## Errors

Every failed request returns the same envelope:

```json theme={null}
{
  "error": {
    "code": "INVALID_PARAMS",
    "message": "prompt: String must contain at least 1 character(s)",
    "trace_id": "01HZY6P8RB4K5C7X9E2N8MDQ4T"
  }
}
```

| Field | Description |
| - | - |
| `code` | Stable machine-readable error code (see below). Safe to branch on in client code. |
| `message` | Human-readable explanation. May include field-level detail from schema validation. |
| `trace_id` | Unique identifier for this request. Always include it when contacting support so we can trace the request end-to-end. |

### Error codes

| Code | HTTP status | When it happens |
| - | - | - |
| `INVALID_PARAMS` | `400` | Request body or query parameters failed schema validation, the body wasn't valid JSON, or a required parameter was missing. |
| `UNAUTHORIZED` | `401` | Missing, malformed, or revoked credential in the `Authorization` header. |
| `FORBIDDEN` | `403` | Credential is valid but not permitted to mutate this thread -- `PATCH` or `DELETE` issued against a thread the caller did not create. |
| `NOT_FOUND` | `404` | Resource doesn't exist, the caller isn't permitted to read it, or the public API feature flag isn't enabled for the organization. |
| `RATE_LIMITED` | `429` | Request quota exceeded. See [Rate limits](#rate-limits). |
| `INTERNAL_ERROR` | `500` | Unexpected server-side failure. Retry with exponential backoff; contact support with the `trace_id` if the issue persists. |

<Note>
  `NOT_FOUND` is returned both when a resource truly doesn't exist and when the
  caller lacks permission to see it. This is intentional -- it avoids leaking
  the existence of threads the caller can't access.
</Note>

***

## Rate limits

<Note>
  The default quota is **10,000 requests per organization per day**.
</Note>

Limits are applied at the **organization** level across every credential
and endpoint. Requests over the limit return:

```
HTTP/2 429
Content-Type: application/json

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded",
    "trace_id": "01HZY6P8RB4K5C7X9E2N8MDQ4T"
  }
}
```

Back off with exponential delay and jitter so retries don't synchronize,
and treat `429` as a signal to reduce request rate across the entire
organization -- the limit is org-wide, not per-credential. If your
integration consistently approaches the quota, contact
[support@endgame.io](mailto:support@endgame.io) to review.

***

## Create a thread

`POST /api/v1/threads`

Creates a new thread in the caller's organization. The `prompt` is
required -- it's persisted as the first user message and triggers the
assistant's response to generate asynchronously.

**Request body**

| Field | Type | Required | Description |
| - | - | - | - |
| `prompt` | string (min 1) | ✅ | First user message on the thread. |
| `title` | string (min 1) | | Explicit title. Auto-generated from `prompt` if omitted. |
| `accountId` | string | | Associate the thread with an account ID. |
| `secondaryId` | string | | Secondary linkage (e.g. opportunity, user). Settable on create only. |

**Example**

```bash theme={null}
curl -X POST https://app.endgame.io/api/v1/threads \
  -H "Authorization: Bearer eak_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "What accounts does my team own?"}'
```

```json theme={null}
{
  "thread": {
    "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
    "title": "What accounts does my team own?",
    "createdAt": "2026-04-22T14:32:10.000Z",
    "updatedAt": null,
    "accountId": null,
    "secondaryId": null,
    "published": false,
    "deleted": false,
    "threadUrl": null
  },
  "messageId": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4V",
  "responseMessageId": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4W"
}
```

Poll [`GET /api/v1/threads/{id}`](#get-a-thread) until the returned
`status.state` is `idle` (success) or `error`.

<Note>
  Requires a user-scoped API key. Org-wide API keys and M2M tokens receive `403
      FORBIDDEN`.
</Note>

***

## Get a thread

`GET /api/v1/threads/{id}`

Fetches a thread, every message on it, and a derived run status.

**Path parameters**

| Name | Type | Description |
| - | - | - |
| `id` | string | Thread identifier. |

**Example**

```bash theme={null}
curl https://app.endgame.io/api/v1/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T \
  -H "Authorization: Bearer eak_your_api_key_here"
```

```json theme={null}
{
  "thread": {
    "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
    "title": "What accounts does my team own?",
    "createdAt": "2026-04-22T14:32:10.000Z",
    "updatedAt": "2026-04-22T14:32:18.000Z",
    "accountId": null,
    "secondaryId": null,
    "published": false,
    "deleted": false,
    "threadUrl": "https://app.endgame.io/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
  },
  "messages": [
    {
      "id": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4V",
      "threadId": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
      "role": "user",
      "content": "What accounts does my team own?",
      "status": null,
      "createdAt": "2026-04-22T14:32:10.000Z",
      "completedAt": null,
      "steps": null,
      "sources": null,
      "attachments": null,
      "model": null
    },
    {
      "id": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4W",
      "threadId": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
      "role": "assistant",
      "content": "Your team owns 42 accounts. The five largest by ARR are...",
      "status": "completed",
      "createdAt": "2026-04-22T14:32:11.000Z",
      "completedAt": "2026-04-22T14:32:18.000Z",
      "steps": [
        { "description": "Looking up accounts owned by your team" },
        { "description": "Ranking by annualized revenue" }
      ],
      "sources": null,
      "attachments": null,
      "model": "claude-opus-4-7"
    }
  ],
  "status": {
    "state": "idle",
    "activeMessageId": null,
    "latestUpdate": null,
    "stepCount": 2
  }
}
```

The `status` object summarizes the latest assistant message so callers
don't have to re-derive it:

| `state` | Meaning |
| - | - |
| `idle` | No assistant work pending -- either the latest assistant message finished, or there are none yet. |
| `in_progress` | Assistant is still generating. `latestUpdate` describes the most recent step (or `"Thinking"`). |
| `error` | Latest assistant message failed. |

Individual message `status` can be `in_progress`, `corroborating`,
`completed`, `failed`, or `cancelled` (always `null` for `user` messages).

***

## List threads

`GET /api/v1/threads`

Lists threads visible to the caller, ordered by most recent activity
first (`updatedAt` when present, otherwise `createdAt`).

**Query parameters**

| Name | Type | Default | Description |
| - | - | - | - |
| `limit` | integer (1-100) | `25` | Maximum number of threads to return on this page. |
| `cursor` | string | -- | Opaque cursor from a previous response's `nextCursor`. |
| `accountId` | string | -- | Filter to threads associated with this account. |

**Example**

```bash theme={null}
curl "https://app.endgame.io/api/v1/threads?limit=50" \
  -H "Authorization: Bearer eak_your_api_key_here"
```

```json theme={null}
{
  "threads": [
    {
      "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
      "title": "What accounts does my team own?",
      "createdAt": "2026-04-22T14:32:10.000Z",
      "updatedAt": "2026-04-22T14:32:18.000Z",
      "accountId": null,
      "secondaryId": null,
      "published": false,
      "deleted": false,
      "threadUrl": "https://app.endgame.io/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
    }
  ],
  "nextCursor": null,
  "truncated": false
}
```

**Response fields**

| Field | Type | Description |
| - | - | - |
| `threads` | `Thread[]` | Page of threads in most-recent-activity-first order. |
| `nextCursor` | `string` \| `null` | Cursor to pass on the next request. `null` when there are no more pages. |
| `truncated` | `boolean` | `true` when the organization has more threads than the server-side pagination window can walk. Narrow with `accountId` to reach the rest. |

**Pagination**

Walks are ordered by most recent activity first (`updatedAt` when
present, otherwise `createdAt`, with `id` as a tiebreaker) -- a thread
whose title was just renamed jumps to the top. Continue requesting pages
with the previous response's `nextCursor` until it comes back `null`.

* Treat `cursor` and `nextCursor` as **opaque**. The internal shape may
  change between releases; don't parse or construct them yourself, and
  URL-encode when passing as a query parameter.
* A **malformed** cursor returns `400 INVALID_PARAMS` rather than
  silently falling back to page 1 -- treat it as a programming bug, not
  a transient error.
* Pages are **stable** across concurrent writes: a thread created
  mid-walk won't cause duplicates or skips for the remainder of the walk.
* When `truncated` is `true`, the walk hit the server-side window before
  covering every visible thread. Narrow with `accountId` to reach the
  rest. `truncated` is `false` for any org whose thread
  count fits inside the window (the common case).

**Visibility**

What shows up in the list depends on the scope of your credential -- see
the [permissions matrix](/api-reference/authentication#scope-and-permissions)
for the full rules.

***

## Rename a thread

`PATCH /api/v1/threads/{id}`

Renames a thread. Only `title` is writable -- unknown fields are
rejected with `400 INVALID_PARAMS`.

**Path parameters**

| Name | Type | Description |
| - | - | - |
| `id` | string | Thread identifier. |

**Request body**

| Field | Type | Required | Description |
| - | - | - | - |
| `title` | string (min 1) | ✅ | New title. |

**Example**

```bash theme={null}
curl -X PATCH https://app.endgame.io/api/v1/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T \
  -H "Authorization: Bearer eak_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"title": "Book of business review — Q2"}'
```

```json theme={null}
{
  "thread": {
    "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
    "title": "Book of business review — Q2",
    "createdAt": "2026-04-22T14:32:10.000Z",
    "updatedAt": "2026-04-22T15:10:44.000Z",
    "accountId": null,
    "secondaryId": null,
    "published": false,
    "deleted": false,
    "threadUrl": "https://app.endgame.io/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
  }
}
```

<Note>
  Requires a user-scoped API key; org-wide API keys and M2M tokens receive `403
      FORBIDDEN`. Users can only rename threads they created -- attempting to rename
  another user's thread also returns `403 FORBIDDEN`, even when the thread is
  published.
</Note>

***

## Delete a thread

`DELETE /api/v1/threads/{id}`

Soft-deletes a thread. The record is preserved server-side but will no
longer appear in `GET /api/v1/threads` or be readable via
`GET /api/v1/threads/{id}`.

**Path parameters**

| Name | Type | Description |
| - | - | - |
| `id` | string | Thread identifier. |

**Example**

```bash theme={null}
curl -X DELETE https://app.endgame.io/api/v1/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T \
  -H "Authorization: Bearer eak_your_api_key_here"
```

```json theme={null}
{
  "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
  "deleted": true
}
```

<Note>
  Requires a user-scoped API key; org-wide API keys and M2M tokens receive `403
      FORBIDDEN`. Users can only delete threads they created.
</Note>

***

## Data shapes

### Thread

| Field | Type | Description |
| - | - | - |
| `id` | string | Stable thread identifier. |
| `title` | string | Human-readable title. |
| `createdAt` | ISO 8601 datetime | When the thread was created. |
| `updatedAt` | ISO 8601 datetime \| null | Last update time. `null` if never updated -- distinguishes "just created" from "updated once at creation". |
| `accountId` | string \| null | Associated account ID. |
| `secondaryId` | string \| null | Secondary linkage (opportunity, user, etc). Settable on create only. |
| `published` | boolean | Whether the thread is published to the organization. |
| `deleted` | boolean | Whether the thread has been soft-deleted. |
| `threadUrl` | string \| null | Deep link into the Endgame app. |

### ThreadMessage

| Field | Type | Description |
| - | - | - |
| `id` | string | Message identifier. |
| `threadId` | string | Parent thread ID. |
| `role` | `"user"` \| `"assistant"` | Message role. |
| `content` | string | Message text. |
| `status` | enum \| null | Always `null` for user messages. Assistant values: `in_progress`, `corroborating`, `completed`, `failed`, `cancelled`. |
| `createdAt` | ISO 8601 datetime | When the message was created. |
| `completedAt` | ISO 8601 datetime \| null | When the message reached a terminal state, if any. |
| `steps` | array \| null | Reasoning steps the assistant emitted while generating. |
| `sources` | array \| null | Source documents referenced by the assistant. |
| `attachments` | array \| null | User-supplied attachments. |
| `model` | string \| null | Identifier of the producing model, if applicable. |

### ThreadStatus

| Field | Type | Description |
| - | - | - |
| `state` | `"idle"` \| `"in_progress"` \| `"error"` | Derived top-level state -- see the table under [Get a thread](#get-a-thread). |
| `activeMessageId` | string \| null | ID of the assistant message currently generating, if `state` is `in_progress`. |
| `latestUpdate` | string \| null | Most recent step description, or `"Thinking"` before any step is emitted. |
| `stepCount` | integer | Number of reasoning steps on the active assistant message. |


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