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

# Compatibility entities

> The legacy polymorphic entity route retained for existing workspace and MCP integrations.

`/api/entities` is the legacy general read/write surface over workspace
records. One endpoint serves every entity type — initiatives, workstreams,
milestones, tasks, decisions, artifacts, runs, goals, and more — selected by a
`type` parameter. Existing MCP and workspace integrations may still use it.

```text theme={"dark"}
https://useorgx.com/api/entities
```

<Note>
  This endpoint lives outside the `/api/v1` namespace and outside the published
  OpenAPI document. It is retained for compatibility only. New integrations
  should use the dedicated `/api/v1` operation for the resource they need; the
  OpenAPI document is the machine contract.
</Note>

## Authentication

All three methods require a personal API key or an authenticated MCP connection:

```http theme={"dark"}
Authorization: Bearer oxk_...
```

With an API key, reads and writes are scoped to the key owner's records. The
`user_id` parameter must match the key's identity; a mismatch returns `403`.

## Methods

| Method  | Purpose                          |
| ------- | -------------------------------- |
| `GET`   | List or fetch records by `type`  |
| `POST`  | Create one record                |
| `PATCH` | Update one record by `type`+`id` |

There is no `DELETE` method on this endpoint. See
[deletion and terminal states](#deletion-and-terminal-states).

## Entity type vocabulary

The `type` parameter accepts these values. Each maps to one underlying table;
the label and body columns show which field names the type actually stores
(generic `title`/`name` and `summary`/`description` aliases are mapped for
you on write).

| `type`              | Label field    | Body field    | Status field + values                                                                                            |
| ------------------- | -------------- | ------------- | ---------------------------------------------------------------------------------------------------------------- |
| `initiative`        | `title`        | `summary`     | `status`: draft, active, blocked, paused, completed, archived                                                    |
| `workstream`        | `name`         | `summary`     | `status`: not\_started, active, blocked, paused, completed                                                       |
| `milestone`         | `title`        | `description` | `status`: planned, in\_progress, completed, at\_risk, cancelled                                                  |
| `task`              | `title`        | `description` | `status`: todo, in\_progress, done, blocked                                                                      |
| `stream`            | `name`         | `description` | `status`: pending, ready, active, blocked, completed, failed, paused                                             |
| `project`           | `name`         | `description` | `status`: draft, active, archived                                                                                |
| `objective`         | `title`        | `description` | `status`: active, paused, completed, archived                                                                    |
| `decision`          | `title`        | `summary`     | `status`: pending, approved, declined, superseded, cancelled (plus legacy `rejected`)                            |
| `artifact`          | `name`         | `description` | `status`: draft, in\_review, approved, changes\_requested, superseded, archived, eval\_passed, rejected          |
| `run`               | `title`        | `summary`     | `status`: draft, planned, awaiting\_approval, running, blocked, paused, completed, failed, cancelled, archived   |
| `blocker`           | `title`        | `description` | `status`: open, resolved, dismissed                                                                              |
| `goal`              | `title`        | `description` | `status`: draft, active, at\_risk, blocked, achieved, missed, descoped, pivoted                                  |
| `person`            | `display_name` | `description` | `relationship_stage`: stranger, prospect, conversation, design\_partner, active\_client, paused, churned, alumni |
| `business`          | `legal_name`   | `description` | `engagement_stage`: unknown, qualified, engaged, active, paused, churned, alumni                                 |
| `relationship`      | `role_title`   | `description` | `relationship_lifecycle_stage` (checked at the database)                                                         |
| `workspace`         | `name`         | `description` | none                                                                                                             |
| `playbook`          | `title`        | `description` | `status`: draft, active, archived                                                                                |
| `workflow`          | `name`         | `description` | `status`: draft, active, paused, completed                                                                       |
| `skill`             | `name`         | `description` | `status`: draft, active, archived                                                                                |
| `plan_session`      | `title`        | `description` | `status`: active, completed, abandoned                                                                           |
| `prospect`          | `name`         | `description` | `status`: identified, engaged, qualified, audit\_booked, audit\_completed, closed\_won, closed\_lost, archived   |
| `opportunity`       | `name`         | `description` | `status`: draft, qualified, audit\_scheduled, audit\_completed, offer\_made, closed\_won, closed\_lost           |
| `bug_report`        | `title`        | `description` | `status`: open, triaged, in\_progress, resolved, closed, wont\_fix                                               |
| `launch_checkpoint` | `name`         | `description` | `decision`: pending, go, hold, fallback                                                                          |
| `studio_brand`      | `name`         | `description` | `ingestion_status`: pending, processing, ready, failed                                                           |
| `studio_content`    | `title`        | `description` | `status`: pending, generating, ready, failed, exported                                                           |

Two additional read-only types are served without a table lookup: `agent`
(the built-in agent roster, filterable by `domain`) and `video_template`.
The alias `issue` is accepted and normalized to `blocker`.

## GET — list and fetch

```bash theme={"dark"}
curl "https://useorgx.com/api/entities?type=task&status=in_progress&limit=20" \
  -H "Authorization: Bearer $ORGX_API_KEY"
```

```bash theme={"dark"}
curl "https://useorgx.com/api/entities?type=initiative&include_relationships=true&count=true" \
  -H "Authorization: Bearer $ORGX_API_KEY"
```

### Query parameters

| Parameter                | Meaning                                                                                                                                |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                   | Required. One of the vocabulary values above.                                                                                          |
| `id`                     | Fetch one record.                                                                                                                      |
| `ids`                    | Comma-separated UUID list, up to 100.                                                                                                  |
| `status`                 | Filter on the type's status field; must be one of that type's valid values.                                                            |
| `initiative_id`          | Scope filter for `milestone`, `workstream`, `stream`, `task`, `decision`, `run` (and artifact metadata matches).                       |
| `workstream_id`          | Scope filter for `task` (and artifact metadata matches).                                                                               |
| `workspace_id`           | Workspace scope (UUID). Rows without a workspace remain visible for supported types.                                                   |
| `search` (alias `query`) | Case-insensitive text match over the type's label and body fields.                                                                     |
| `fields`                 | Comma-separated column subset; `id` is always included.                                                                                |
| `limit`                  | Default 20, maximum 100.                                                                                                               |
| `offset`                 | Default 0.                                                                                                                             |
| `order_by`               | One of `created_at`, `updated_at`, `sequence`, `due_date`, `priority`, `status`, `title`, `name`, or `natural` (hierarchy types only). |
| `order_direction`        | `asc` or `desc` (default `desc`).                                                                                                      |
| `include_relationships`  | `true` to embed child rows (for example an initiative's workstreams, milestones, and tasks).                                           |
| `count`                  | `true` to compute `pagination.total`; otherwise `total` is `-1`.                                                                       |

### Response envelope

```json theme={"dark"}
{
  "type": "task",
  "data": [
    {
      "id": "6f4e8a34-9f2f-4a3e-8d5b-2f1c9f7f2e1a",
      "title": "Review the launch plan",
      "status": "in_progress",
      "milestone_id": "0a4b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d",
      "workstream_id": "1b5c2d3e-4f5a-6b7c-8d9e-0f1a2b3c4d5e",
      "initiative_id": "2c6d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
      "priority": "medium",
      "created_at": "2026-08-18T16:04:11.000Z",
      "updated_at": "2026-08-19T09:12:45.000Z",
      "workspace_id": "3d7e4f5a-6b7c-8d9e-0f1a-2b3c4d5e6f7a"
    }
  ],
  "ordering": { "order_by": "created_at", "order_direction": "desc" },
  "pagination": { "total": -1, "limit": 20, "offset": 0, "has_more": false }
}
```

## POST — create

The body is flat: `type` plus the record's fields. `owner_id` defaults to the
API key's identity.

```bash theme={"dark"}
curl https://useorgx.com/api/entities \
  -X POST \
  -H "Authorization: Bearer $ORGX_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "initiative",
    "title": "Q3 onboarding revamp",
    "summary": "Reduce time-to-first-work for new workspaces.",
    "idempotency_key": "onboarding-revamp-2026q3"
  }'
```

Creation rules that matter:

* **Initiative idempotency.** `idempotency_key` (up to 120 characters) replays
  the existing initiative with `_dedup: true` and `_replayed: true` instead of
  inserting a duplicate.
* **Hierarchy dedup.** Creating a `workstream`, `milestone`, or `task` whose
  label already exists (case-insensitive) inside the same parent scope returns
  the existing row with `_dedup: true` rather than a sibling duplicate.
* **Hierarchy parents.** `workstream` requires `initiative_id`; `task` and
  `milestone` resolve their parents from `milestone_id` / `workstream_id` /
  `initiative_id`.
* **Guarded types.** `blocker` creation is refused here (blockers are raised by
  runs). `decision` creation may not set a non-`pending` status or any
  server-owned resolution field. `run` creation may not set `status`,
  `started_at`, `completed_at`, or `cancelled_at`. `artifact` creation may not
  set `approved` or `rejected` — those assert a human ruling; an automated
  reviewer writes `eval_passed` instead.

The success envelope is `{ "type": ..., "data": { ... } }` with the created
row in `data` (also spread at the top level for older clients). Its `data.id`
is the UUID you use everywhere else.

## PATCH — update

The body is flat: `type`, `id`, plus the fields to change.

```bash theme={"dark"}
curl https://useorgx.com/api/entities \
  -X PATCH \
  -H "Authorization: Bearer $ORGX_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "task",
    "id": "6f4e8a34-9f2f-4a3e-8d5b-2f1c9f7f2e1a",
    "status": "in_progress",
    "priority": "high"
  }'
```

Update guards, enforced per type:

* **Decision**: proposal-field updates are available through the MCP decision
  tool while a decision is `pending`; a personal API key receives `403`. Only proposal fields
  (`title`, `summary`, `description`, `priority`, `due_at`,
  `recommended_action`, `blocks_task`, `estimate`, `urgency`,
  `urgency_score`) are patchable, and only while `pending` (`409`
  otherwise). Approving or declining is a human action — see the
  [decision page](/docs/api/entities/decision).
* **Run**: `status` and timestamp fields are rejected (`403`); control a run
  through [`POST /api/v1/runs/{runId}/actions/{action}`](/docs/api/entities/run).
* **Blocker**: not patchable at all; blockers close through their resolve and
  dismiss lifecycle.
* **Artifact**: `approved` and `rejected` are rejected (`403`); a machine
  reviewer writes `eval_passed`.
* **Task**: `done` tasks are terminal for automated updates; a `409` tells you
  to reopen deliberately first.

## Deletion and terminal states

`/api/entities` has no `DELETE` method, and hard deletion is not part of the
API-key REST contract. Use terminal statuses for API-key workflows. The MCP
`orgx_act` tool can perform the additional lifecycle actions available to an
authenticated MCP connection.

With an API key, use terminal statuses instead:

| Goal                      | Do this                                                                           |
| ------------------------- | --------------------------------------------------------------------------------- |
| Remove an initiative      | `PATCH` `status: "archived"`                                                      |
| Remove a milestone        | `PATCH` `status: "cancelled"`                                                     |
| Remove a run              | `POST /api/v1/runs/{runId}/actions/cancel`                                        |
| Retire an artifact        | `PATCH` `status: "superseded"` or `"archived"`                                    |
| Withdraw a decision       | Resolution is human-only; see the [decision page](/docs/api/entities/decision)         |
| Pause or cancel hierarchy | `POST /api/v1/lifecycle` with `level`, `id`, `action` (pause/resume/retry/cancel) |

## Lifecycle actions — `POST /api/v1/lifecycle`

One route pauses, resumes, retries, or cancels any node of the hierarchy. It
takes exactly three fields, all required:

| Field    | Type                                               | Meaning             |
| -------- | -------------------------------------------------- | ------------------- |
| `level`  | `initiative` `workstream` `milestone` `task` `run` | Which kind of node. |
| `id`     | UUID                                               | The node's ID.      |
| `action` | `pause` `resume` `retry` `cancel`                  | What to do.         |

Note the field names: this route takes `level` and `id`, **not** `entity_type`
and `entity_id` (those belong to the artifact and receipt surfaces). There is
no `status` or target-state field — the target state is implied by `action`,
and cascades to child runs.

```bash theme={"dark"}
curl https://useorgx.com/api/v1/lifecycle \
  -X POST \
  -H "Authorization: Bearer $ORGX_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "level": "initiative",
    "id": "2c6d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
    "action": "pause"
  }'
```

The response is a bare object — no `{ data, meta }` envelope — returned with
`200` when `ok` is `true` and `422` when it is `false`:

```json theme={"dark"}
{
  "ok": true,
  "action": "pause",
  "level": "initiative",
  "id": "2c6d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
  "affected": { "nodes": 4, "runsPaused": 2, "runsCancelled": 0, "redispatched": 0 },
  "message": "Initiative paused."
}
```

A refusal adds `error` and `blockReasons` to the lifecycle result. Lifecycle
errors use the same structured error envelope as the rest of `/api/v1`.

## Where the IDs come from

| ID you need     | Obtain it from                                                                                  |
| --------------- | ----------------------------------------------------------------------------------------------- |
| any entity `id` | `POST /api/entities` response `data.id`, or `GET /api/entities?type=...` listing rows           |
| `workspace_id`  | `GET /api/v1/me` → `data.default_workspace_id` or `data.workspaces[].id` (API key)              |
| `initiative_id` | `POST /api/v1/initiatives` response `data.initiativeId`, or `GET /api/entities?type=initiative` |
| `milestone_id`  | `POST /api/v1/initiatives` response `data.milestoneId`, or `GET /api/entities?type=milestone`   |
| `workstream_id` | `POST /api/v1/initiatives` response `data.workstreamId`, or `GET /api/entities?type=workstream` |
| `owner_id`      | Defaults to your API key identity; you rarely need to send it.                                  |

## MCP equivalents

| MCP tool       | Relationship to this endpoint                                            |
| -------------- | ------------------------------------------------------------------------ |
| `orgx_search`  | Typed searches call `GET /api/entities` with the same parameters.        |
| `orgx_write`   | Creates call `POST /api/entities`; updates call `PATCH /api/entities`.   |
| `orgx_inspect` | Reads `GET /api/entities?type=...&id=...` plus MCP execution context.    |
| `orgx_act`     | Runs the lifecycle actions available to an authenticated MCP connection. |
