{
  "openapi": "3.1.0",
  "info": {
    "title": "Endgame Public API",
    "version": "1.0.0",
    "description": "Create and manage Endgame threads over HTTPS."
  },
  "servers": [
    {
      "url": "https://app.endgame.io"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/threads": {
      "post": {
        "operationId": "createThread",
        "summary": "Create a thread",
        "description": "Creates a new thread in the caller's organization. Requires a user-scoped API key; org-wide API keys and M2M applications receive `403 FORBIDDEN` during beta. The `prompt` is required -- it's persisted as the first user message and triggers the assistant's response to generate asynchronously. Poll `GET /api/v1/threads/{id}` until the derived `status.state` is `idle` (or `error`).",
        "tags": [
          "Threads"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateThreadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Thread created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateThreadResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidParams"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "get": {
        "operationId": "listThreads",
        "summary": "List threads",
        "description": "Lists threads visible to the caller, ordered by most recent activity first (`updatedAt` when present, otherwise `createdAt`). Personal keys see their own threads plus every org-published thread; the org-wide principal (shared by org-wide API keys and M2M applications) sees every org-published thread.",
        "tags": [
          "Threads"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of threads to return (1-100, default 25).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from a previous response's `nextCursor`. Omit for the first page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "description": "Optional filter: only return threads associated with this account ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of threads.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListThreadsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidParams"
          }
        }
      }
    },
    "/api/v1/threads/{id}": {
      "get": {
        "operationId": "getThread",
        "summary": "Get a thread",
        "description": "Retrieves a thread, its messages, and its derived run status. Callers can only fetch threads they are permitted to read -- threads created by other users under a user-scoped key return `404 NOT_FOUND`.",
        "tags": [
          "Threads"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ThreadId"
          }
        ],
        "responses": {
          "200": {
            "description": "Thread, messages, and derived status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetThreadResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateThread",
        "summary": "Update a thread",
        "description": "Renames a thread. Only `title` is writable. Requires a user-scoped API key; org-wide API keys and M2M applications receive `403 FORBIDDEN` during beta. Users can only rename threads they created -- attempts to rename another user's thread also return `403 FORBIDDEN`, even when the thread is published.",
        "tags": [
          "Threads"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ThreadId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateThreadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated thread.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateThreadResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidParams"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "delete": {
        "operationId": "deleteThread",
        "summary": "Delete a thread",
        "description": "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}`. Requires a user-scoped API key; org-wide API keys and M2M applications receive `403 FORBIDDEN` during beta. Users can only delete threads they created.",
        "tags": [
          "Threads"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ThreadId"
          }
        ],
        "responses": {
          "200": {
            "description": "Deletion acknowledged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteThreadResponse"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "One of: an Endgame API key prefixed `eak_` (created from Settings → API Keys with a Personal or Org-wide scope), or a WorkOS access token from an Endgame-provisioned M2M application (created from Settings → Applications and exchanged via the `client_credentials` grant)."
      }
    },
    "parameters": {
      "ThreadId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Thread identifier.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Thread": {
        "type": "object",
        "description": "Public representation of a thread.",
        "required": [
          "id",
          "title",
          "createdAt",
          "updatedAt",
          "accountId",
          "secondaryId",
          "published",
          "deleted",
          "threadUrl"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable thread identifier.",
            "readOnly": true,
            "example": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
          },
          "title": {
            "type": "string",
            "description": "Human-readable title. Auto-generated from the first prompt when a thread is created without an explicit title.",
            "example": "What accounts does my team own?"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of thread creation.",
            "readOnly": true,
            "example": "2026-04-22T14:32:10.000Z"
          },
          "updatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO 8601 timestamp of the last update. `null` if never updated.",
            "readOnly": true,
            "example": "2026-04-22T14:35:02.000Z"
          },
          "accountId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Associated account ID, if any.",
            "example": "0018b00000abCdEfGhI"
          },
          "secondaryId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Secondary linkage (e.g. opportunity, user). Settable on create only.",
            "example": null
          },
          "published": {
            "type": "boolean",
            "description": "Whether the thread is published to the organization.",
            "readOnly": true,
            "example": false
          },
          "deleted": {
            "type": "boolean",
            "description": "Whether the thread has been soft-deleted.",
            "readOnly": true,
            "example": false
          },
          "threadUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Deep link into the Endgame app for this thread.",
            "readOnly": true,
            "example": "https://app.endgame.io/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
          }
        },
        "example": {
          "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
          "title": "What accounts does my team own?",
          "createdAt": "2026-04-22T14:32:10.000Z",
          "updatedAt": "2026-04-22T14:35:02.000Z",
          "accountId": "0018b00000abCdEfGhI",
          "secondaryId": null,
          "published": false,
          "deleted": false,
          "threadUrl": "https://app.endgame.io/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
        }
      },
      "ThreadMessage": {
        "type": "object",
        "description": "A single message on a thread.",
        "required": [
          "id",
          "threadId",
          "role",
          "content",
          "status",
          "createdAt",
          "completedAt",
          "steps",
          "sources",
          "attachments",
          "model"
        ],
        "properties": {
          "id": {
            "type": "string",
            "readOnly": true,
            "example": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4U"
          },
          "threadId": {
            "type": "string",
            "readOnly": true,
            "example": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
          },
          "role": {
            "type": "string",
            "enum": [
              "assistant",
              "user"
            ],
            "readOnly": true,
            "example": "assistant"
          },
          "content": {
            "type": "string",
            "readOnly": true,
            "example": "Your team owns 42 accounts. The five largest by ARR are..."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "in_progress",
              "corroborating",
              "completed",
              "failed",
              "cancelled",
              null
            ],
            "description": "Lifecycle status of the message. Always `null` for `user` messages; non-null for assistant messages. `in_progress` and `corroborating` mean the assistant is still processing; `completed` is terminal success; `failed` means an error was hit; `cancelled` means the user or system aborted the message.",
            "readOnly": true,
            "example": "completed"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "example": "2026-04-22T14:32:11.000Z"
          },
          "completedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "readOnly": true,
            "example": "2026-04-22T14:32:18.000Z"
          },
          "steps": {
            "type": [
              "array",
              "null"
            ],
            "description": "Reasoning steps emitted while the assistant was generating.",
            "items": {
              "type": "object",
              "required": [
                "description"
              ],
              "properties": {
                "description": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            },
            "readOnly": true,
            "example": [
              {
                "description": "Looking up accounts owned by your team"
              },
              {
                "description": "Ranking by annualized revenue"
              }
            ]
          },
          "sources": {
            "type": [
              "array",
              "null"
            ],
            "description": "Source documents referenced by the assistant.",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "readOnly": true,
            "example": null
          },
          "attachments": {
            "type": [
              "array",
              "null"
            ],
            "description": "User-supplied attachments associated with the message.",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "readOnly": true,
            "example": null
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier of the model that produced the message, if applicable.",
            "readOnly": true,
            "example": "claude-opus-4-7"
          }
        }
      },
      "ThreadStatus": {
        "type": "object",
        "description": "Derived run status based on the latest assistant message.",
        "required": [
          "state",
          "activeMessageId",
          "latestUpdate",
          "stepCount"
        ],
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "idle",
              "in_progress",
              "error"
            ],
            "description": "`idle` when no assistant work is pending (or no assistant messages exist yet), `in_progress` while the assistant is still generating, `error` if the most recent assistant message failed.",
            "example": "idle"
          },
          "activeMessageId": {
            "type": [
              "string",
              "null"
            ],
            "description": "ID of the assistant message currently being generated, if `state` is `in_progress`.",
            "example": null
          },
          "latestUpdate": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the most recent reasoning step, or `\"Thinking\"` if the assistant hasn't emitted a step yet.",
            "example": null
          },
          "stepCount": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of reasoning steps emitted on the active assistant message.",
            "example": 0
          }
        }
      },
      "CreateThreadRequest": {
        "type": "object",
        "description": "Parameters for creating a thread. `prompt` is required; `title` auto-generates from it if omitted.",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "minLength": 1,
            "description": "First user message on the thread. Persisted immediately and triggers an assistant response that generates asynchronously.",
            "example": "What accounts does my team own?"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "Explicit title. If omitted, the title is auto-generated from the prompt.",
            "example": "Book of business review"
          },
          "accountId": {
            "type": "string",
            "description": "Associate the thread with an account ID.",
            "example": "0018b00000abCdEfGhI"
          },
          "secondaryId": {
            "type": "string",
            "description": "Secondary linkage (e.g. opportunity, user).",
            "example": "0068b00000abCdEfGhI"
          }
        },
        "example": {
          "prompt": "What accounts does my team own?"
        }
      },
      "CreateThreadResponse": {
        "type": "object",
        "required": [
          "thread"
        ],
        "properties": {
          "thread": {
            "$ref": "#/components/schemas/Thread"
          },
          "messageId": {
            "type": "string",
            "description": "ID of the user message persisted from `prompt`.",
            "example": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4V"
          },
          "responseMessageId": {
            "type": "string",
            "description": "ID of the in-flight assistant response message. Poll `GET /api/v1/threads/{id}` until this message's `status` is `completed` or `failed`.",
            "example": "msg_01HZY6P8RB4K5C7X9E2N8MDQ4W"
          }
        },
        "example": {
          "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"
        }
      },
      "ListThreadsResponse": {
        "type": "object",
        "required": [
          "threads",
          "nextCursor",
          "truncated"
        ],
        "properties": {
          "threads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Thread"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque cursor for the next page. `null` when there are no more pages.",
            "example": "MjAyNi0wNC0yMlQxNDozNTowMi4wMDBafHRocl8wMUhaWTZQOFJCNEs1QzdYOUUyTjhNRFE0VA=="
          },
          "truncated": {
            "type": "boolean",
            "description": "`true` when the organization has more threads than the server-side pagination window can walk. Narrow the result with `accountId` to retrieve the threads this page can't surface.",
            "example": false
          }
        },
        "example": {
          "threads": [
            {
              "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
              "title": "What accounts does my team own?",
              "createdAt": "2026-04-22T14:32:10.000Z",
              "updatedAt": "2026-04-22T14:35:02.000Z",
              "accountId": null,
              "secondaryId": null,
              "published": false,
              "deleted": false,
              "threadUrl": "https://app.endgame.io/threads/thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
            }
          ],
          "nextCursor": null,
          "truncated": false
        }
      },
      "GetThreadResponse": {
        "type": "object",
        "required": [
          "thread",
          "messages",
          "status"
        ],
        "properties": {
          "thread": {
            "$ref": "#/components/schemas/Thread"
          },
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ThreadMessage"
            }
          },
          "status": {
            "$ref": "#/components/schemas/ThreadStatus"
          }
        },
        "example": {
          "thread": {
            "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
            "title": "What accounts does my team own?",
            "createdAt": "2026-04-22T14:32:10.000Z",
            "updatedAt": "2026-04-22T14:35:02.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
          }
        }
      },
      "UpdateThreadRequest": {
        "type": "object",
        "description": "Only `title` is writable. Unknown fields are rejected with `INVALID_PARAMS`.",
        "additionalProperties": false,
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "description": "New title. Must be at least one character.",
            "example": "Book of business review — Q2"
          }
        },
        "example": {
          "title": "Book of business review — Q2"
        }
      },
      "UpdateThreadResponse": {
        "type": "object",
        "required": [
          "thread"
        ],
        "properties": {
          "thread": {
            "$ref": "#/components/schemas/Thread"
          }
        }
      },
      "DeleteThreadResponse": {
        "type": "object",
        "required": [
          "id",
          "deleted"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T"
          },
          "deleted": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Always `true` on a successful delete.",
            "example": true
          }
        },
        "example": {
          "id": "thr_01HZY6P8RB4K5C7X9E2N8MDQ4T",
          "deleted": true
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "trace_id"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "INVALID_PARAMS",
                  "UNAUTHORIZED",
                  "FORBIDDEN",
                  "NOT_FOUND",
                  "RATE_LIMITED",
                  "INTERNAL_ERROR"
                ],
                "description": "Stable machine-readable error code.",
                "example": "INVALID_PARAMS"
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation.",
                "example": "prompt: String must contain at least 1 character(s)"
              },
              "trace_id": {
                "type": "string",
                "description": "Unique identifier for the request. Include in support requests.",
                "example": "01HZY6P8RB4K5C7X9E2N8MDQ4T"
              }
            }
          }
        },
        "example": {
          "error": {
            "code": "INVALID_PARAMS",
            "message": "prompt: String must contain at least 1 character(s)",
            "trace_id": "01HZY6P8RB4K5C7X9E2N8MDQ4T"
          }
        }
      }
    },
    "responses": {
      "InvalidParams": {
        "description": "Request body or query parameters failed validation. See [Errors](/api-reference/endpoints#errors) for the full error envelope and code list.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Credential is valid but not permitted. Either the operation requires a user-scoped API key (org-wide credentials cannot mutate threads during beta), or the caller is user-scoped but did not create the thread. See [Errors](/api-reference/endpoints#errors) for the full error envelope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}