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

# Collections, Records y Entities

> Endpoints REST para el sustrato operacional: collections configuradas, records tipados y entities cross-collection. Las lecturas son active-only y brief por defecto; archive, restore y purge son rutas de ciclo de vida explícitas y gobernadas.

Todas las rutas están bajo la base URL (`/api/v1`) y requieren autenticación. Las lecturas son de miembro del workspace; las escrituras requieren el scope `work:write` por OAuth; **purge es solo owner/admin**. Las lecturas son **active-only, acotadas y brief por defecto** — los objetos archived solo aparecen con un opt-in explícito. Ver [Collections](/es/concepts/collections) para el modelo.

## Collections

| Método   | Ruta                                                  | Perm                  | Propósito                                                                                                                                                                               |
| -------- | ----------------------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST`   | `/workspaces/:slug/collections`                       | member (`work:write`) | Crea una collection                                                                                                                                                                     |
| `GET`    | `/workspaces/:slug/collections`                       | member                | Lista collections (`?status=&owner=&updated_after=&limit=&cursor=`). Por defecto `active`; bare array, o `{items, shown, has_more, nextCursor}` cuando hay un param de paging           |
| `GET`    | `/workspaces/:slug/collections/search`                | member                | Búsqueda por intención (`?q=&status=&include_archived=&owner=&updated_after=&limit=&cursor=`). `q` obligatorio; los `items[]` llevan `score`; active-only salvo `include_archived=true` |
| `GET`    | `/workspaces/:slug/collections/doctor`                | member                | Audita collections (`?full`); solo lectura, hallazgos acotados                                                                                                                          |
| `GET`    | `/workspaces/:slug/collections/:id`                   | member                | Detalle de la collection (`?view=brief\|full`). **Brief por defecto**; `full` devuelve config + `stage_counts`                                                                          |
| `GET`    | `/workspaces/:slug/collections/:id/context`           | member                | Resuelve el criterion Knowledge (`{criterion, missing}`)                                                                                                                                |
| `GET`    | `/workspaces/:slug/collections/:id/connector-mapping` | member                | Lee la config del connector mapping                                                                                                                                                     |
| `PATCH`  | `/workspaces/:slug/collections/:id`                   | member (`work:write`) | Actualiza config. Rechaza `status=archived` (`409`) — usa archive/restore                                                                                                               |
| `PUT`    | `/workspaces/:slug/collections/:id/connector-mapping` | member (`work:write`) | Setea el connector mapping; valida campos contra `record_schema`; nunca corre una acción del provider                                                                                   |
| `POST`   | `/workspaces/:slug/collections/:id/archive`           | member (`work:write`) | Retira de forma reversible una collection activa; `version += 1`; archived es inmutable                                                                                                 |
| `POST`   | `/workspaces/:slug/collections/:id/restore`           | member (`work:write`) | Restaura una collection archived a `active`                                                                                                                                             |
| `DELETE` | `/workspaces/:slug/collections/:id`                   | owner/admin           | Purga una collection archived (`?dry_run=&expected_version=`). CAS, auditado, idempotente, preserva distilled Notes                                                                     |

Cuerpo de creación (`CreateCollectionDto`): `name` (obligatorio), `archetype` (obligatorio, uno de `pipeline`, `analysis`, `content`), `record_schema`, `views`, `criterion_rel_slugs`, `distill_policy`, `owner_clerk_id`. El update acepta `name`, `record_schema`, `views`, `criterion_rel_slugs`, `distill_policy` — un `status` de `archived` devuelve `409` y nombra la ruta de ciclo de vida que usar.

## Records

Ruta base `/workspaces/:slug/collections/:id`.

| Método   | Ruta                    | Perm                  | Propósito                                                                                                                                                                                             |
| -------- | ----------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST`   | `.../records`           | member (`work:write`) | Agrega un record; devuelve el record (con `context_outcome` cuando el stage es terminal)                                                                                                              |
| `GET`    | `.../records`           | member                | Lista records (`?status=&entity_id=&drifted=&updated_after=&view=&limit=&cursor=`). Dual-shape: bare array (sin param nuevo), o `{records, nextCursor}`                                               |
| `GET`    | `.../retrieve`          | member                | Records más criterion en una sola llamada acotada (`?query=&fields=&status=&entity_id=&drifted=&updated_after=&view=&limit=&cursor=`); devuelve `{records, nextCursor, criterion, criterion_missing}` |
| `GET`    | `.../records/:recordId` | member                | Detalle del record                                                                                                                                                                                    |
| `PATCH`  | `.../records/:recordId` | member (`work:write`) | Actualiza un record; devuelve `context_outcome` en una transición a terminal                                                                                                                          |
| `DELETE` | `.../records/:recordId` | member (`work:write`) | Elimina un record (`?dry_run=`). Idempotente; preserva distilled Notes                                                                                                                                |

Cuerpo de record (`CreateRecordDto` / `UpdateRecordDto`): `fields`, `status`, `field_meta`, `entity_id`, y `drifted` en el update. El `status` de un record se valida contra los stages de la collection. `entity_id` es una propiedad top-level del record, **nunca** un campo dentro de `fields` (pasa `""` en update para limpiar el link). Una transición a un stage terminal dispara el `distill_policy` y puede adjuntar un `context_outcome` (`created` · `already_exists` · `skipped` · `failed`) al record — best-effort, nunca bloquea la escritura.

## Entities

| Método | Ruta                             | Perm                  | Propósito                 |
| ------ | -------------------------------- | --------------------- | ------------------------- |
| `POST` | `/workspaces/:slug/entities`     | member (`work:write`) | Hace upsert de una entity |
| `GET`  | `/workspaces/:slug/entities`     | member                | Lista entities (`?kind`)  |
| `GET`  | `/workspaces/:slug/entities/:id` | member                | Detalle de la entity      |

Cuerpo de upsert (`UpsertEntityDto`): `kind` (obligatorio), `name` (obligatorio), `dedup_key`, `attributes`. El upsert es idempotente sobre `(kind, dedup_key)` — re-upsertar el mismo par mergea `name`/`attributes` en vez de crear un duplicado.

```bash theme={"theme":"github-light"}
curl -X POST https://api.trybrein.com/api/v1/workspaces/acme/entities \
  -H "x-api-key: drift_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"kind":"company","name":"Acme","dedup_key":"acme.com"}'
```

## Paginación y errores

`list` y `search` de collections paginan por **keyset cursor** (`limit` 1–50, default 20; `cursor` opaco del `nextCursor` previo); `list` es dual-shape por back-compat — bare array cuando no hay param de paging/filter, el sobre `{items, nextCursor}` en caso contrario. `list` y `retrieve` de records paginan por keyset (`limit` 1–100, default 25; keyset sobre `created_at, id`). La lista de entities es un array acotado (sin cursor). Un `status` inválido (fuera de los stages de la collection) o un `archetype` inválido, o un campo de cuerpo desconocido, devuelve `400 VALIDATION_FAILED`. Un `fields` JSON malformado en `retrieve` se ignora silenciosamente, nunca erroriza. Ver [errores](/es/api/errors) para el sobre.

## Ciclo de vida: archive y purge

* **`POST .../:id/archive`** retira una collection activa. **`POST .../:id/restore`** reviven una collection `archived` a `active`. Ambos incrementan `version` y se auditan. Una collection archived es **inmutable** — `PATCH`, las escrituras de records y `retrieve` devuelven `409 PROTECTED_RESOURCE`.
* **`DELETE .../:id?dry_run=true`** previsualiza el impacto (`distilled_notes_preserved` cuenta las distilled Notes que **sobreviven** al borrado; `entity_links_removed` cuenta los record links rotos). **`DELETE .../:id?expected_version=<n>`** ejecuta el purge con compare-and-set; un `expected_version` que no coincide devuelve `409 VERSION_CONFLICT`. **Solo owner/admin**, auditado, idempotente — un reintento tras el purge devuelve `already_absent`.

El safe **delete de records** sigue la misma forma: `DELETE .../records/:recordId` solo elimina de una collection no archived; `?dry_run=true` previsualiza el Entity link removido y las distilled Notes preservadas (sobreviven al borrado, no se re-evalúan). El delete está gateado por membresía del workspace (no owner/admin), auditado, idempotente — un reintento tras el borrado devuelve `already_absent`.

## Relacionado

* [Collections](/es/concepts/collections) - arquetipos, tipos de campo y la costura del criterion.
* [CLI: Collections, Records y Entities](/es/cli/collections) - la superficie de línea de comandos.
* [MCP: Collections y operaciones](/es/mcp/work) - la superficie MCP.
