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

# Tipos de ítem personalizados

> Crea y gestiona tus propios tipos de documento con clasificación, validación y extracción configurables vía la API v2.

Los **tipos de ítem personalizados** permiten que tu cuenta defina sus propios tipos de documento, cada uno con procesos configurables de clasificación, validación y extracción. Trébol gestiona el ciclo de vida completo a través del endpoint `/v2/custom-item-types`.

## Cuándo usarlos

Usa tipos de ítem personalizados cuando necesites:

* Procesar un tipo de ítem que Trébol no soporta de forma estándar.
* Definir reglas de clasificación, validación o extracción específicas para tu negocio.
* Controlar el esquema de salida (JSON) de la extracción.

<Note>
  Esta funcionalidad complementa las [extracciones personalizadas](/docs/producto/guias/extracciones-personalizadas). Las extracciones personalizadas aplican sobre tipos ya soportados; los tipos de ítem personalizados crean un tipo nuevo desde cero.
</Note>

## Conceptos clave

### Tipo y procesos

Un **tipo de ítem personalizado** (`custom_item_type`) agrupa uno o más **procesos**. Cada proceso define una tarea que Trébol ejecuta sobre el documento:

| Proceso          | Descripción                                                                     | Cardinalidad           |
| ---------------- | ------------------------------------------------------------------------------- | ---------------------- |
| `classification` | Describe el documento para que Trébol lo identifique al clasificar.             | Exactamente 1 por tipo |
| `validation`     | Define una regla de validación. Cada regla tiene su propio `process_reference`. | Hasta 20 por tipo      |
| `extraction`     | Define campos a extraer y produce un `json_schema` de salida.                   | Hasta 5 por tipo       |

Al crear un tipo, el proceso de clasificación se crea automáticamente de forma atómica. Solo puede editarse mediante PATCH; no puede añadirse de nuevo ni eliminarse.

### Identificadores

Cada tipo y cada proceso exponen dos identificadores:

* **`id`** — generado por Trébol, inmutable. Úsalo en las rutas de la API (ej. `cit_abc123`, `ccp_def456`).
* **`name`** (solo en tipos) — identificador que defines tú (no una etiqueta legible; para eso está `friendly_name`). Debe empezar con el prefijo `cit_` y no puede contener espacios (usa `_` o `-` como separador). Único por cuenta entre tipos activos y archivados. Se usa como valor de `type` al enviar ítems en verificaciones.
* **`process_reference`** (solo en procesos) — etiqueta elegida por ti, única dentro del mismo tipo. Editable vía PATCH.

### Ciclo de vida

```mermaid theme={"dark"}
stateDiagram-v2
    [*] --> active: POST /v2/custom-item-types
    active --> archived: PATCH status = archived
    archived --> active: PATCH status = active
    active --> [*]: DELETE (permanente)
    archived --> [*]: DELETE (permanente)
```

* **`active`** — el tipo acepta documentos en verificaciones.
* **`archived`** — el tipo está pausado. Sigue apareciendo en el listado y puede reactivarse en cualquier momento con PATCH `status: "active"`. Verificaciones que lo referencien son rechazadas mientras esté archivado.
* **Eliminado (DELETE)** — el tipo y todos sus procesos se borran de forma permanente e irreversible. Para pausar un tipo sin perderlo, archívalo en lugar de eliminarlo.

### Mejora automática

Al crear o actualizar un proceso puedes incluir `auto_improve` (por defecto `true`). Cuando está activo, Trébol mejora automáticamente tus instrucciones con IA en segundo plano para todos los tipos de proceso. Para procesos de extracción, también genera un `json_schema`.

<Info>
  Al **crear** un proceso de extracción no puedes enviar `json_schema`: en la creación el esquema lo genera la mejora automática, por eso `auto_improve` no se puede desactivar (`auto_improve: false` devuelve error 400). Si quieres definir o ajustar el esquema manualmente, hazlo **después** con un PATCH sobre el proceso (campo `json_schema`).
</Info>

***

## Autenticación

Todos los endpoints requieren tu API key en el header `x-api-key`.

***

## Crear un tipo

<ParamField body="name" type="string" required>
  Identificador del tipo de documento que defines tú. Debe empezar con `cit_` y no puede contener espacios (usa `_` o `-` como separador; ej. `"cit_contrato_arrendamiento"`). Único por cuenta entre tipos activos y archivados.
</ParamField>

<ParamField body="user_input" type="string" required>
  Instrucciones para identificar este tipo de documento.
</ParamField>

<ParamField body="friendly_name" type="string" required>
  Nombre legible para interfaces. Entre 2 y 255 caracteres.
</ParamField>

<ParamField body="auto_improve" type="boolean" default="true">
  Cuando es `false`, Trébol usa tus instrucciones tal cual, sin mejora automática.
</ParamField>

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X POST https://api.gotrebol.com/v2/custom-item-types \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "cit_contrato_arrendamiento",
      "user_input": "Este documento es un contrato de arrendamiento inmobiliario firmado ante notario.",
      "friendly_name": "Contrato de arrendamiento"
    }'
  ```

  ```javascript JavaScript theme={"dark"}
  const response = await fetch("https://api.gotrebol.com/v2/custom-item-types", {
    method: "POST",
    headers: {
      "x-api-key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "cit_contrato_arrendamiento",
      user_input:
        "Este documento es un contrato de arrendamiento inmobiliario firmado ante notario.",
      friendly_name: "Contrato de arrendamiento",
    }),
  });
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.post(
      "https://api.gotrebol.com/v2/custom-item-types",
      headers={"x-api-key": "YOUR_API_KEY"},
      json={
          "name": "cit_contrato_arrendamiento",
          "user_input": "Este documento es un contrato de arrendamiento inmobiliario firmado ante notario.",
          "friendly_name": "Contrato de arrendamiento",
      },
  )
  ```
</RequestExample>

### Respuesta (201)

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="object" required>
  Tipo de ítem personalizado creado.

  <Expandable title="Propiedades de data">
    <ResponseField name="id" type="string">
      Identificador único generado por Trébol (ej. `cit_abc123`).
    </ResponseField>

    <ResponseField name="name" type="string">
      Clave del tipo asignada en la creación.
    </ResponseField>

    <ResponseField name="friendly_name" type="string">
      Nombre legible para interfaces.
    </ResponseField>

    <ResponseField name="status" type="string">
      Estado del tipo: `active` o `archived`.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      Fecha de creación en formato ISO 8601.
    </ResponseField>

    <ResponseField name="updated_at" type="string">
      Fecha de última actualización en formato ISO 8601.
    </ResponseField>

    <ResponseField name="processes" type="array">
      Procesos vinculados al tipo.

      <Expandable title="Propiedades del proceso">
        <ResponseField name="id" type="string">
          Identificador único del proceso (ej. `ccp_def456`).
        </ResponseField>

        <ResponseField name="process_reference" type="string">
          Etiqueta del proceso asignada por el usuario.
        </ResponseField>

        <ResponseField name="process_type" type="string">
          Tipo de proceso: `classification`, `validation` o `extraction`.
        </ResponseField>

        <ResponseField name="is_active" type="boolean">
          Indica si el proceso está activo.
        </ResponseField>

        <ResponseField name="failure_policy" type="string | null">
          Política de fallo para validaciones. `warning`: el ítem se pausa hasta que se revise el resultado. `hard_stop`: si la regla no se cumple, el ítem se da por finalizado. `null`: el ítem continúa procesándose aunque la regla falle. Para clasificación y extracción siempre es `null`.
        </ResponseField>

        <ResponseField name="active_version_id" type="integer | null">
          ID de la versión activa del proceso.
        </ResponseField>

        <ResponseField name="version_number" type="integer">
          Número secuencial de la versión activa.
        </ResponseField>

        <ResponseField name="created_at" type="string">
          Fecha de creación del proceso.
        </ResponseField>

        <ResponseField name="updated_at" type="string">
          Fecha de última actualización del proceso.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 201 theme={"dark"}
  {
    "success": true,
    "data": {
      "id": "cit_abc123",
      "name": "cit_contrato_arrendamiento",
      "friendly_name": "Contrato de arrendamiento",
      "status": "active",
      "created_at": "2026-01-15T10:00:00.000Z",
      "updated_at": "2026-01-15T10:00:00.000Z",
      "processes": [
        {
          "id": "ccp_def456",
          "process_reference": "cit_contrato_arrendamiento_classification",
          "process_type": "classification",
          "is_active": true,
          "failure_policy": null,
          "active_version_id": 42,
          "version_number": 1,
          "created_at": "2026-01-15T10:00:00.000Z",
          "updated_at": "2026-01-15T10:00:00.000Z"
        }
      ]
    }
  }
  ```
</ResponseExample>

<Warning>
  Las respuestas de escritura (POST / PATCH) no incluyen `user_input` ni `json_schema` en los procesos. Usa GET para leer el contenido completo de cada proceso.
</Warning>

<Info>
  La respuesta incluye un proceso de clasificación que Trébol crea junto con el tipo. Su `process_reference` se genera automáticamente como `<name>_classification` (por eso no lo envías al crear): es estable y predecible. No cambia si más adelante renombras el tipo, y —como cualquier proceso— puedes renombrarlo con PATCH, aunque normalmente no hace falta.
</Info>

### Errores

| Código | Condición                                                        |
| ------ | ---------------------------------------------------------------- |
| 400    | `name`, `user_input` o `friendly_name` faltante o inválido       |
| 400    | `name` no empieza con `cit_` o contiene espacios                 |
| 400    | `friendly_name` fuera del rango de 2 a 255 caracteres            |
| 409    | `name` ya existe en la cuenta (entre tipos activos y archivados) |

***

## Listar tipos

```
GET /v2/custom-item-types
```

Devuelve todos los tipos de tu cuenta (activos y archivados) con sus procesos. Ordenados por fecha de creación descendente. Tamaño de página fijo: 10.

<ParamField query="next" type="string">
  Token de cursor para obtener la siguiente página. Devuelto en la respuesta cuando hay más resultados.
</ParamField>

### Respuesta (200)

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="array" required>
  Lista de tipos de ítem personalizados de la cuenta (activos y archivados).

  <Expandable title="Propiedades de cada tipo">
    <ResponseField name="id" type="string">
      Identificador único del tipo.
    </ResponseField>

    <ResponseField name="name" type="string">
      Clave del tipo.
    </ResponseField>

    <ResponseField name="friendly_name" type="string">
      Nombre legible para interfaces.
    </ResponseField>

    <ResponseField name="status" type="string">
      Estado del tipo: `active` o `archived`.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      Fecha de creación en formato ISO 8601.
    </ResponseField>

    <ResponseField name="updated_at" type="string">
      Fecha de última actualización en formato ISO 8601.
    </ResponseField>

    <ResponseField name="processes" type="array">
      Procesos vinculados al tipo. En respuestas GET incluye `user_input` y `json_schema`.

      <Expandable title="Propiedades del proceso">
        <ResponseField name="id" type="string">
          Identificador único del proceso.
        </ResponseField>

        <ResponseField name="process_reference" type="string">
          Etiqueta del proceso.
        </ResponseField>

        <ResponseField name="process_type" type="string">
          Tipo de proceso: `classification`, `validation` o `extraction`.
        </ResponseField>

        <ResponseField name="is_active" type="boolean">
          Indica si el proceso está activo.
        </ResponseField>

        <ResponseField name="failure_policy" type="string | null">
          Política de fallo para validaciones. `warning`: el ítem se pausa hasta que se revise el resultado. `hard_stop`: si la regla no se cumple, el ítem se da por finalizado. `null`: el ítem continúa procesándose aunque la regla falle. Para clasificación y extracción siempre es `null`.
        </ResponseField>

        <ResponseField name="active_version_id" type="integer | null">
          ID de la versión activa.
        </ResponseField>

        <ResponseField name="version_number" type="integer">
          Número secuencial de la versión activa.
        </ResponseField>

        <ResponseField name="user_input" type="string">
          Instrucciones del proceso (solo en respuestas GET).
        </ResponseField>

        <ResponseField name="json_schema" type="object | null">
          Esquema JSON de salida para procesos de extracción (solo en respuestas GET).
        </ResponseField>

        <ResponseField name="created_at" type="string">
          Fecha de creación del proceso.
        </ResponseField>

        <ResponseField name="updated_at" type="string">
          Fecha de última actualización del proceso.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="next" type="string">
  Token de cursor para la siguiente página. Solo presente cuando hay más resultados.
</ResponseField>

<ResponseExample>
  ```json 200 theme={"dark"}
  {
    "success": true,
    "data": [
      {
        "id": "cit_abc123",
        "name": "cit_contrato_arrendamiento",
        "friendly_name": "Contrato de arrendamiento",
        "status": "active",
        "created_at": "...",
        "updated_at": "...",
        "processes": [
          {
            "id": "ccp_def456",
            "process_reference": "cit_contrato_arrendamiento_classification",
            "process_type": "classification",
            "is_active": true,
            "failure_policy": null,
            "active_version_id": 42,
            "version_number": 1,
            "user_input": "Este documento es un contrato de arrendamiento...",
            "json_schema": null,
            "created_at": "...",
            "updated_at": "..."
          }
        ]
      }
    ],
    "next": "eyJjcmVhdGVkQXQiOi..."
  }
  ```
</ResponseExample>

<Info>
  Las respuestas de lectura (GET) incluyen `user_input` y `json_schema` en cada proceso.
</Info>

***

## Obtener un tipo

```
GET /v2/custom-item-types/{id}
```

Devuelve un tipo con todos sus procesos. Misma estructura que un elemento individual del listado. Los tipos archivados se devuelven normalmente.

| Código | Condición          |
| ------ | ------------------ |
| 404    | Tipo no encontrado |

***

## Actualizar un tipo

```
PATCH /v2/custom-item-types/{id}
```

Actualiza campos del tipo. Debes enviar al menos un campo.

<ParamField body="name" type="string">
  Renombra el tipo. No puede contener espacios. Única por cuenta entre tipos activos y archivados.
</ParamField>

<ParamField body="friendly_name" type="string">
  Actualiza el nombre legible. Entre 2 y 255 caracteres.
</ParamField>

<ParamField body="status" type="string">
  Estado del tipo. Valores permitidos:

  * `"archived"`: pausa el tipo. Sigue apareciendo en el listado y puede reactivarse en cualquier momento.
  * `"active"`: reactiva un tipo archivado.
</ParamField>

<Tip>
  Para pausar un tipo temporalmente usa `status: "archived"` (es reversible). Para borrarlo de forma permanente, usa [Eliminar un tipo](#eliminar-un-tipo).
</Tip>

<RequestExample>
  ```bash cURL theme={"dark"}
  # Archivar un tipo (pausarlo). Para reactivarlo, envía "active".
  curl -X PATCH https://api.gotrebol.com/v2/custom-item-types/cit_abc123 \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{ "status": "archived" }'
  ```

  ```javascript JavaScript theme={"dark"}
  const response = await fetch(
    "https://api.gotrebol.com/v2/custom-item-types/cit_abc123",
    {
      method: "PATCH",
      headers: {
        "x-api-key": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      // Para reactivarlo: { status: "active" }
      body: JSON.stringify({ status: "archived" }),
    }
  );
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.patch(
      "https://api.gotrebol.com/v2/custom-item-types/cit_abc123",
      headers={"x-api-key": "YOUR_API_KEY"},
      # Para reactivarlo: {"status": "active"}
      json={"status": "archived"},
  )
  ```
</RequestExample>

### Respuesta (200)

Devuelve solo los campos del tipo, sin procesos.

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="object" required>
  Tipo actualizado (sin procesos).

  <Expandable title="Propiedades de data">
    <ResponseField name="id" type="string">
      Identificador único del tipo.
    </ResponseField>

    <ResponseField name="name" type="string">
      Clave del tipo.
    </ResponseField>

    <ResponseField name="friendly_name" type="string">
      Nombre legible para interfaces.
    </ResponseField>

    <ResponseField name="status" type="string">
      Estado actual: `active` o `archived`.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      Fecha de creación en formato ISO 8601.
    </ResponseField>

    <ResponseField name="updated_at" type="string">
      Fecha de última actualización en formato ISO 8601.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 200 theme={"dark"}
  {
    "success": true,
    "data": {
      "id": "cit_abc123",
      "name": "cit_contrato_arrendamiento_v2",
      "friendly_name": "Contrato de arrendamiento",
      "status": "archived",
      "created_at": "...",
      "updated_at": "..."
    }
  }
  ```
</ResponseExample>

### Errores

| Código | Condición                                                        |
| ------ | ---------------------------------------------------------------- |
| 400    | Ningún campo proporcionado, valor inválido o `name` vacío        |
| 400    | `status` con valor no permitido (solo `"active"` o `"archived"`) |
| 400    | `friendly_name` fuera del rango de 2 a 255 caracteres            |
| 404    | Tipo no encontrado                                               |
| 409    | `name` colisiona con otro tipo activo o archivado de la cuenta   |

<Tip>
  Si los valores enviados ya coinciden con los actuales, el recurso no cambia y `updated_at` se mantiene.
</Tip>

***

## Eliminar un tipo

```
DELETE /v2/custom-item-types/{id}
```

Elimina el tipo de forma **permanente e irreversible**, junto con todos sus procesos.

<Warning>
  Esta operación no se puede deshacer. Para pausar un tipo sin perderlo (y poder reactivarlo después), archívalo con PATCH `status: "archived"` en lugar de eliminarlo.
</Warning>

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X DELETE https://api.gotrebol.com/v2/custom-item-types/cit_abc123 \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={"dark"}
  const response = await fetch(
    "https://api.gotrebol.com/v2/custom-item-types/cit_abc123",
    {
      method: "DELETE",
      headers: { "x-api-key": "YOUR_API_KEY" },
    }
  );
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.delete(
      "https://api.gotrebol.com/v2/custom-item-types/cit_abc123",
      headers={"x-api-key": "YOUR_API_KEY"},
  )
  ```
</RequestExample>

### Respuesta (200)

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="object" required>
  Contiene el identificador del tipo eliminado.

  <Expandable title="Propiedades de data">
    <ResponseField name="id" type="string">
      Identificador único del tipo eliminado.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 200 theme={"dark"}
  {
    "success": true,
    "data": { "id": "cit_abc123" }
  }
  ```
</ResponseExample>

| Código | Condición                                  |
| ------ | ------------------------------------------ |
| 401    | No autorizado. API key inválida o faltante |
| 404    | Tipo no encontrado o ya eliminado          |

***

## Agregar un proceso

```
POST /v2/custom-item-types/{id}/processes
```

Agrega un proceso de validación o extracción a un tipo existente. Hasta 5 procesos de extracción y 20 de validación por tipo.

<ParamField body="process_type" type="string" required>
  `"validation"` o `"extraction"`.
</ParamField>

<ParamField body="process_reference" type="string" required>
  Etiqueta del proceso. Única dentro del mismo tipo.
</ParamField>

<ParamField body="user_input" type="string" required>
  Instrucciones escritas por ti para este proceso.
</ParamField>

<ParamField body="auto_improve" type="boolean">
  Para procesos de extracción, debe enviarse como `true` (enviar `false` devuelve error 400: en la creación el `json_schema` lo genera la mejora automática y no se acepta enviarlo en esta petición; para definirlo manualmente, usa un PATCH posterior). Para procesos de validación, es opcional (por defecto `true`).
</ParamField>

<ParamField body="failure_policy" type="string | null">
  Solo para validación. `"warning"`: el ítem se pausa hasta que se revise el resultado. `"hard_stop"`: si la regla no se cumple, el ítem se da por finalizado. `null`: el ítem continúa procesándose aunque la regla falle. Se rechaza si se envía en otro tipo de proceso.
</ParamField>

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X POST https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "process_type": "extraction",
      "process_reference": "extraer_montos",
      "user_input": "Extrae todos los montos monetarios del contrato, incluyendo renta mensual y depósito.",
      "auto_improve": true
    }'
  ```

  ```javascript JavaScript theme={"dark"}
  const response = await fetch(
    "https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes",
    {
      method: "POST",
      headers: {
        "x-api-key": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        process_type: "extraction",
        process_reference: "extraer_montos",
        user_input:
          "Extrae todos los montos monetarios del contrato, incluyendo renta mensual y depósito.",
        auto_improve: true,
      }),
    }
  );
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.post(
      "https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes",
      headers={"x-api-key": "YOUR_API_KEY"},
      json={
          "process_type": "extraction",
          "process_reference": "extraer_montos",
          "user_input": "Extrae todos los montos monetarios del contrato, incluyendo renta mensual y depósito.",
          "auto_improve": True,
      },
  )
  ```
</RequestExample>

### Respuesta (201)

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="object" required>
  Proceso creado.

  <Expandable title="Propiedades de data">
    <ResponseField name="id" type="string">
      Identificador único del proceso (ej. `ccp_ghi789`).
    </ResponseField>

    <ResponseField name="process_reference" type="string">
      Etiqueta del proceso.
    </ResponseField>

    <ResponseField name="process_type" type="string">
      Tipo de proceso: `classification`, `validation` o `extraction`.
    </ResponseField>

    <ResponseField name="is_active" type="boolean">
      Indica si el proceso está activo.
    </ResponseField>

    <ResponseField name="failure_policy" type="string | null">
      Política de fallo para validaciones. `warning`: el ítem se pausa hasta que se revise el resultado. `hard_stop`: si la regla no se cumple, el ítem se da por finalizado. `null`: el ítem continúa procesándose aunque la regla falle. Para clasificación y extracción siempre es `null`.
    </ResponseField>

    <ResponseField name="active_version_id" type="integer | null">
      ID de la versión activa del proceso.
    </ResponseField>

    <ResponseField name="version_number" type="integer">
      Número secuencial de la versión activa.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      Fecha de creación del proceso.
    </ResponseField>

    <ResponseField name="updated_at" type="string">
      Fecha de última actualización del proceso.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 201 theme={"dark"}
  {
    "success": true,
    "data": {
      "id": "ccp_ghi789",
      "process_reference": "extraer_montos",
      "process_type": "extraction",
      "is_active": true,
      "failure_policy": null,
      "active_version_id": 99,
      "version_number": 1,
      "created_at": "...",
      "updated_at": "..."
    }
  }
  ```
</ResponseExample>

### Errores

| Código | Condición                                                             |
| ------ | --------------------------------------------------------------------- |
| 400    | Campos requeridos faltantes o inválidos                               |
| 400    | `auto_improve: false` en un proceso de extracción                     |
| 400    | `failure_policy` enviado en un proceso que no es de validación        |
| 404    | Tipo padre no encontrado o eliminado                                  |
| 409    | `process_reference` ya existe en este tipo                            |
| 409    | `user_input` idéntico ya en uso en otro proceso del mismo tipo        |
| 409    | Se alcanzó el límite de procesos (5 de extracción o 20 de validación) |

### Ejemplo: proceso de validación con `failure_policy`

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X POST https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "process_type": "validation",
      "process_reference": "validar_firmas",
      "user_input": "Verifica que el contrato contenga las firmas de ambas partes y del notario público.",
      "failure_policy": "hard_stop"
    }'
  ```
</RequestExample>

### Ejemplo de respuesta de error

Cuando ocurre un conflicto (por ejemplo, `process_reference` duplicado), la respuesta sigue esta estructura:

<ResponseExample>
  ```json 409 theme={"dark"}
  {
    "success": false,
    "message": "process with identifier 'validar_firmas' already exists.",
    "code": "DUPLICATE_RESOURCE",
    "timestamp": "2026-01-15T10:00:00.000Z"
  }
  ```
</ResponseExample>

***

## Obtener un proceso

```
GET /v2/custom-item-types/{id}/processes/{processId}
```

Devuelve un proceso con su versión activa, incluyendo `user_input` y `json_schema`.

### Respuesta (200)

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="object" required>
  Proceso con su versión activa.

  <Expandable title="Propiedades de data">
    <ResponseField name="id" type="string">
      Identificador único del proceso.
    </ResponseField>

    <ResponseField name="process_reference" type="string">
      Etiqueta del proceso.
    </ResponseField>

    <ResponseField name="process_type" type="string">
      Tipo de proceso: `classification`, `validation` o `extraction`.
    </ResponseField>

    <ResponseField name="is_active" type="boolean">
      Indica si el proceso está activo.
    </ResponseField>

    <ResponseField name="failure_policy" type="string | null">
      Política de fallo para validaciones. `warning`: el ítem se pausa hasta que se revise el resultado. `hard_stop`: si la regla no se cumple, el ítem se da por finalizado. `null`: el ítem continúa procesándose aunque la regla falle. Para clasificación y extracción siempre es `null`.
    </ResponseField>

    <ResponseField name="active_version_id" type="integer | null">
      ID de la versión activa.
    </ResponseField>

    <ResponseField name="version_number" type="integer">
      Número secuencial de la versión activa.
    </ResponseField>

    <ResponseField name="user_input" type="string">
      Instrucciones escritas por el usuario para este proceso.
    </ResponseField>

    <ResponseField name="json_schema" type="object | null">
      Esquema JSON de salida. Solo presente en procesos de extracción.

      <Expandable title="Propiedades del json_schema">
        <ResponseField name="type" type="string">
          Tipo raíz del esquema (generalmente `object`).
        </ResponseField>

        <ResponseField name="properties" type="object">
          Campos definidos en el esquema con su tipo y descripción.
        </ResponseField>

        <ResponseField name="required" type="array">
          Lista de campos obligatorios.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="created_at" type="string">
      Fecha de creación del proceso.
    </ResponseField>

    <ResponseField name="updated_at" type="string">
      Fecha de última actualización del proceso.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 200 theme={"dark"}
  {
    "success": true,
    "data": {
      "id": "ccp_ghi789",
      "process_reference": "extraer_montos",
      "process_type": "extraction",
      "is_active": true,
      "failure_policy": null,
      "active_version_id": 99,
      "version_number": 1,
      "user_input": "Extrae todos los montos monetarios del contrato...",
      "json_schema": {
        "type": "object",
        "properties": {
          "renta_mensual": { "type": "number", "description": "Monto de la renta mensual" },
          "deposito": { "type": "number", "description": "Monto del depósito" }
        },
        "required": ["renta_mensual", "deposito"]
      },
      "created_at": "...",
      "updated_at": "..."
    }
  }
  ```
</ResponseExample>

### Resolución

Para que el GET responda correctamente:

1. La clasificación existe y no está archivado.
2. El proceso existe y no está eliminado.
3. La versión activa del proceso tiene `user_input` no nulo.

Si alguna condición falla, Trébol devuelve 404.

<Warning>
  Tipos archivados (`status: "archived"`) devuelven 404 al consultar sus procesos, aunque el tipo en sí siga siendo consultable via `GET /v2/custom-item-types/{id}`.
</Warning>

***

## Actualizar un proceso

```
PATCH /v2/custom-item-types/{id}/processes/{processId}
```

Actualiza un proceso. Debes enviar al menos un campo. `process_type` y `id` no se pueden cambiar.

<ParamField body="process_reference" type="string">
  Renombra la etiqueta. Única dentro del mismo tipo.
</ParamField>

<ParamField body="is_active" type="boolean">
  Activa o pausa el proceso sin eliminarlo. El proceso de clasificación no se puede pausar.
</ParamField>

<ParamField body="user_input" type="string">
  Nuevas instrucciones. Si el texto difiere del valor activo, se crea una nueva versión del proceso que pasa a ser la activa.
</ParamField>

<ParamField body="json_schema" type="object">
  Solo para procesos de extracción. Define el esquema JSON de salida. Enviarlo crea una nueva versión del proceso. Enviarlo en un proceso que no es de extracción devuelve 400.
</ParamField>

<ParamField body="auto_improve" type="boolean" default="true">
  Solo aplica cuando cambias `user_input`. Si es `false`, Trébol no ejecuta mejora automática y conserva tus instrucciones tal cual.
</ParamField>

<ParamField body="failure_policy" type="string | null">
  Solo para validación. `"warning"`: el ítem se pausa hasta que se revise el resultado. `"hard_stop"`: si la regla no se cumple, el ítem se da por finalizado. `null`: el ítem continúa procesándose aunque la regla falle.
</ParamField>

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X PATCH https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes/ccp_ghi789 \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "user_input": "Extrae todos los montos monetarios del contrato: renta mensual, depósito, penalización por mora y total anual.",
      "auto_improve": true
    }'
  ```

  ```javascript JavaScript theme={"dark"}
  const response = await fetch(
    "https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes/ccp_ghi789",
    {
      method: "PATCH",
      headers: {
        "x-api-key": "YOUR_API_KEY",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        user_input:
          "Extrae todos los montos monetarios del contrato: renta mensual, depósito, penalización por mora y total anual.",
        auto_improve: true,
      }),
    }
  );
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.patch(
      "https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes/ccp_ghi789",
      headers={"x-api-key": "YOUR_API_KEY"},
      json={
          "user_input": "Extrae todos los montos monetarios del contrato: renta mensual, depósito, penalización por mora y total anual.",
          "auto_improve": True,
      },
  )
  ```
</RequestExample>

<Info>
  El proceso de clasificación se edita igual que cualquier otro: obtén su `id` con [Obtener un tipo](#obtener-un-tipo) (es el proceso con `process_type: "classification"`) y haz PATCH sobre `/processes/{processId}` cambiando su `user_input`.
</Info>

### Versiones del proceso

Cuando el PATCH modifica `user_input` (y el texto difiere del valor activo), Trébol crea una **nueva versión** del proceso, que pasa a ser la activa.

Si `auto_improve` es `true` y cambias `user_input`, Trébol lanza la mejora automática en segundo plano.

### Errores

| Código | Condición                                                                           |
| ------ | ----------------------------------------------------------------------------------- |
| 400    | `failure_policy` con valor no nulo en un proceso que no es de validación            |
| 400    | `json_schema` enviado en un proceso que no es de extracción, o con formato inválido |
| 404    | Tipo padre o proceso no encontrado                                                  |
| 409    | `process_reference` colisiona con otro proceso del mismo tipo                       |
| 409    | `user_input` idéntico ya usado en otro proceso del mismo tipo                       |
| 409    | Se intentó pausar (`is_active: false`) el proceso de clasificación                  |

***

## Eliminar un proceso

```
DELETE /v2/custom-item-types/{id}/processes/{processId}
```

Elimina permanentemente un proceso de validación o extracción. El proceso de clasificación no puede eliminarse; intentarlo devuelve error 409. Para cambiar sus instrucciones, usa PATCH sobre el proceso.

### Respuesta (200)

<ResponseField name="success" type="boolean" required>
  Indica si la operación se completó correctamente.
</ResponseField>

<ResponseField name="data" type="object" required>
  Contiene el identificador del proceso eliminado.

  <Expandable title="Propiedades de data">
    <ResponseField name="id" type="string">
      Identificador único del proceso eliminado.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseExample>
  ```json 200 theme={"dark"}
  {
    "success": true,
    "data": { "id": "ccp_ghi789" }
  }
  ```
</ResponseExample>

| Código | Condición                                                        |
| ------ | ---------------------------------------------------------------- |
| 404    | Tipo padre no encontrado, o proceso no encontrado / ya eliminado |
| 409    | Intento de eliminar el proceso de clasificación                  |

<Warning>
  El proceso de clasificación no puede eliminarse. Usa PATCH para actualizar sus instrucciones.
</Warning>

***

## Procesamiento asíncrono

Cuando creas o actualizas un proceso con `auto_improve = true`, Trébol no bloquea la respuesta. En su lugar:

<Steps>
  <Step title="Respuesta inmediata">
    El endpoint devuelve 201 (creación) o 200 (actualización). La respuesta de escritura no incluye `user_input` ni `json_schema`.
  </Step>

  <Step title="Mejora en segundo plano">
    Trébol mejora tus instrucciones con IA para todos los tipos de proceso. Para procesos de extracción, también genera un `json_schema`.
  </Step>

  <Step title="Resultado disponible vía GET (extracción)">
    Para procesos de extracción, consulta el proceso con GET hasta que `json_schema` esté poblado. Para clasificación y validación, el proceso es funcional de inmediato con tus instrucciones originales.
  </Step>
</Steps>

### Cómo saber cuándo terminó la mejora

El mecanismo varía según el tipo de proceso:

| Tipo de proceso                | Señal de finalización                                                                                                                                                                |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Extracción**                 | El GET del proceso devuelve `json_schema` poblado (no `null`). Espera a que esté disponible antes de enviar documentos.                                                              |
| **Clasificación y validación** | No hay señal pública de que la mejora terminó. Trébol usa tus instrucciones originales de inmediato y, cuando la mejora finaliza, cambia internamente a las instrucciones mejoradas. |

<Info>
  Normalmente el `json_schema` lo genera la mejora automática, pero también puedes definirlo tú con el campo `json_schema` en el PATCH del proceso (solo extracción). Otra opción para regenerarlo es cambiar el `user_input` con `auto_improve: true` para que Trébol produzca uno nuevo.
</Info>

***

## Interacción con verificaciones

### Envío de ítems

Al enviar un ítem de verificación que referencia un tipo de ítem personalizado:

1. El `name` debe corresponder a un tipo existente en tu cuenta (activo o archivado).
2. El tipo debe tener `status = 'active'`.

| Código | Causa                                               | Acción                                        |
| ------ | --------------------------------------------------- | --------------------------------------------- |
| 400    | El `name` no corresponde a ningún tipo de la cuenta | Verifica que el tipo existe                   |
| 422    | El tipo tiene `status = 'archived'`                 | Reactiva el tipo con PATCH `status: "active"` |

***

## Ejemplo completo

Este ejemplo crea un tipo de ítem personalizado para contratos de arrendamiento, le agrega una extracción y luego envía un documento para procesar.

<Steps>
  <Step title="Crear el tipo">
    ```bash theme={"dark"}
    curl -X POST https://api.gotrebol.com/v2/custom-item-types \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "cit_contrato_arrendamiento",
        "user_input": "Este documento es un contrato de arrendamiento inmobiliario.",
        "friendly_name": "Contrato de arrendamiento"
      }'
    ```
  </Step>

  <Step title="Agregar un proceso de extracción">
    Usa el `id` del tipo devuelto en el paso 1 (aquí `cit_abc123`).

    ```bash theme={"dark"}
    curl -X POST https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "process_type": "extraction",
        "process_reference": "extraer_datos_contrato",
        "user_input": "Extrae: nombre del arrendador, nombre del arrendatario, monto de renta mensual, fecha de inicio y duración del contrato.",
        "auto_improve": true
      }'
    ```

    La respuesta incluye el `id` del proceso creado (por ejemplo, `ccp_ghi789`). Lo necesitas en el siguiente paso.
  </Step>

  <Step title="Esperar la mejora automática">
    Como se trata de un proceso de extracción, consulta el proceso con GET usando el `id` del paso 2 hasta que `json_schema` esté poblado. Para clasificación y validación, Trébol usa tus instrucciones originales de inmediato y las reemplaza internamente por las mejoradas cuando la mejora termina.

    ```bash theme={"dark"}
    # Sustituye ccp_ghi789 por el id devuelto en el paso 2
    curl https://api.gotrebol.com/v2/custom-item-types/cit_abc123/processes/ccp_ghi789 \
      -H "x-api-key: YOUR_API_KEY"
    ```
  </Step>

  <Step title="Enviar un documento para procesar">
    Crea una verificación usando el `name` del tipo como `type` del ítem.

    ```bash theme={"dark"}
    curl -X POST https://api.gotrebol.com/verifications \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "country": "mx",
        "tag": "empresa-ejemplo-001",
        "items": [
          {
            "type": "cit_contrato_arrendamiento",
            "options": {
              "file_url": "https://ejemplo.com/contrato.pdf"
            }
          }
        ]
      }'
    ```
  </Step>

  <Step title="Consultar los resultados">
    Una vez que la verificación termine de procesarse (puedes saberlo vía [webhook](/docs/guia-devs/webhooks)), consulta los resultados de extracción con los endpoints v2 de lectura:

    * [Obtener sección por etiqueta de empresa](https://docs.gotrebol.com/api-reference/leer-información-de-la-empresa/obtener-sección-por-etiqueta-de-empresa) — `GET /v2/companies/{etiqueta}/{section}` con `section=sources`
    * [Obtener sección por ID de verificación](https://docs.gotrebol.com/api-reference/leer-información-de-la-empresa/obtener-sección-por-id-de-verificación) — `GET /v2/verifications/{verification-id}/{entity}` con `entity=sources`

    Cada fuente incluye tus datos extraídos en el campo `custom_user_prompts`. Ese objeto usa el `process_reference` del proceso como clave. Ejemplo de fragmento en `data.sources`:

    ```json theme={"dark"}
    {
      "custom_user_prompts": {
        "extraer_datos_contrato": {
          "nombre_arrendador": "María López García",
          "nombre_arrendatario": "Carlos Ramírez Soto",
          "renta_mensual": 15000,
          "fecha_inicio": "2026-02-01",
          "duracion_contrato": "12 meses"
        }
      }
    }
    ```

    La clave (`extraer_datos_contrato`) es el `process_reference` que asignaste al proceso de extracción en el paso 2. Como cada ítem de verificación pertenece a un solo tipo, las claves de `custom_user_prompts` de una fuente provienen siempre de ese único tipo; por eso basta con que el `process_reference` sea único dentro del tipo para que no haya colisiones.
  </Step>
</Steps>

***

## Siguientes pasos

<CardGroup cols={2}>
  <Card title="Extracciones personalizadas" href="/docs/producto/guias/extracciones-personalizadas">
    Personaliza la extracción para tipos de documento que Trébol ya soporta.
  </Card>

  <Card title="Reglas de validación" href="/docs/guia-devs/crear-verificaciones/via-api/reglas-validacion">
    Reglas predefinidas y personalizadas para validar documentos.
  </Card>

  <Card title="Tipos de documentos" href="/docs/guia-devs/referencia/tipos-item">
    Lista completa de tipos de documento soportados.
  </Card>

  <Card title="Webhooks" href="/docs/guia-devs/webhooks">
    Recibe notificaciones cuando una verificación termine de procesarse.
  </Card>
</CardGroup>
