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

# Uso de Mission Control

> Consulta el consumo de IA de un workspace (créditos, ejecuciones, adopción) en Mission Control: un periodo, agrupado, filtrado y comparado con el periodo anterior.

Tu token de API debe poder **usar agentes** (`use_agents`) y necesitas acceso a la API en el workspace. Además, el endpoint aplica los permisos de **Mission Control** de tu rol: `mission-control:view` para consultar, y el alcance de uso que te concedieron (tu propio uso, tus equipos o el workspace completo). El alcance se resuelve en el servidor a partir de tu rol; la petición nunca lo amplía.

> [!NOTE]
>
> Este endpoint responde exactamente lo que muestra el panel de Mission Control en Tess, a partir de los mismos datos horarios. Mission Control debe estar habilitado para el workspace, y hay datos desde `freshness.data_available_from`. Un periodo que empieza antes se rechaza, nunca se responde con ceros.

### **Ejemplos de código**

Consumo por modelo de IA en el mes actual, comparado con el periodo anterior:

```http cURL theme={null}
curl --request GET \
  --url 'https://api.tess.im/mission-control/usage?from=2026-10-01&to=2026-10-28&timezone=America/Sao_Paulo&group_by[]=resource&filters[resource_kind][]=model&compare=previous_period&granularity=month&limit=5' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'x-workspace-id: YOUR_WORKSPACE_ID' \
  --header 'Accept: application/json'
```

```javascript Node.js theme={null}
const axios = require('axios');

const config = {
  method: 'get',
  url: 'https://api.tess.im/mission-control/usage',
  params: {
    from: '2026-10-01',
    to: '2026-10-28',
    timezone: 'America/Sao_Paulo',
    'group_by[]': ['resource'],
    'filters[resource_kind][]': ['model'],
    compare: 'previous_period',
    granularity: 'month',
    limit: 5
  },
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-workspace-id': 'YOUR_WORKSPACE_ID',
    'Accept': 'application/json'
  }
};

try {
  const response = await axios(config);
  console.log(response.data.data.totals, response.data.data.groups);
} catch (error) {
  console.error(error.response?.status, error.response?.data);
}
```

```python Python theme={null}
import requests

url = "https://api.tess.im/mission-control/usage"
params = {
    "from": "2026-10-01",
    "to": "2026-10-28",
    "timezone": "America/Sao_Paulo",
    "group_by[]": ["resource"],
    "filters[resource_kind][]": ["model"],
    "compare": "previous_period",
    "granularity": "month",
    "limit": 5,
}
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
    "x-workspace-id": "YOUR_WORKSPACE_ID",
    "Accept": "application/json",
}

response = requests.get(url, params=params, headers=headers)
if response.ok:
    data = response.json()["data"]
    print(data["totals"], data["groups"])
else:
    print(response.status_code, response.json())
```

### **Encabezados**

**x-workspace-id** `integer` *required*

ID del workspace. Debes ser miembro activo del workspace y tener `mission-control:view` en él.

### **Parámetros de consulta**

**from** `date (YYYY-MM-DD)` *required*

Inicio del periodo, fecha local en `timezone` (inclusive).

**to** `date (YYYY-MM-DD)` *required*

Fin del periodo (inclusive). El periodo es de como máximo **93 días** y no puede empezar antes de `freshness.data_available_from`.

**timezone** `string`

Zona horaria IANA de las fechas locales y de los buckets (por ejemplo `America/Sao_Paulo`). Por defecto: la zona horaria de la plataforma.

**granularity** `string`

Tamaño del bucket de `series`: `hour`, `day` (por defecto), `week` o `month`.

**metrics\[]** `array of string`

Métricas a devolver. Por defecto: `consumption_net`, `consumption_charged`, `consumption_refunded`. Disponibles: `consumption_net`, `consumption_charged`, `consumption_refunded`, `executions`, `failed_executions`, `interrupted_executions`, `uses`, `success_rate`, `avg_credits_per_execution`, `avg_credits_per_person`, `active_people`, `active_agents`, `active_autonomous_agents`, `active_days`, `active_business_days`.

**group\_by\[]** `array of string`

Dimensiones de agrupación, como máximo 3: `agent`, `person`, `resource`, `resource_kind`, `execution_type`, `modality`, `activity_category`, `charge_type`, `execution_origin`, `trigger_source`, `agent_origin`. Agrupar por `person` requiere `mission-control:person-data:view`; sin él la consulta se rechaza (403 `person_data_not_allowed`).

**filters\[person]\[]** `array of string`

`me` (tu propio uso), `my_team` (miembros actuales de tus equipos), `my_workspace` (todos en tu alcance) o ids de personas. Los alias no requieren permiso extra; los ids de personas requieren `mission-control:person-data:view` y deben estar dentro de tu alcance.

**filters\[team]\[]** `array of integer`

Ids de equipos. Solo se aceptan los ids listados en `scope.teams` de una respuesta anterior.

**filters\[agent]\[]** `array of integer`

Ids de agentes. Tómalos de `groups[].dimensions.agent.id` de una respuesta anterior agrupada por `agent`.

**filters\[resource]\[]** `array of string`

Recursos como `<kind>:<name>`, por ejemplo `model:gpt-5`, `tool:web_search`, `connector:googlesheets`. Tómalos de una respuesta anterior agrupada por `resource`.

**filters\[resource\_kind]\[]** `array of string`

`model`, `tool`, `connector`, `upload`, `kb`, `memory`, `voice` u `other`. Usa `["model"]` para restringir una agrupación por `resource` a los modelos de IA.

**filters\[modality]\[]** `array of string`

`chat`, `image`, `video`, `audio`, `upload`, `tools` u `other`.

**filters\[activity\_category]\[]** `array of string`

`agents`, `tools`, `connectors` o `kb`.

**filters\[agent\_origin]\[]** `array of string`

`standard` o `cowork` (agentes de Cowork / Empleados Digitales).

**filters\[trigger\_source]\[]** `array of string`

Quién inició la ejecución: `human`, `scheduler`, `autopilot`, `automation`, `api` o `embed`.

**filters\[status]\[]** `array of string`

Resultado de la ejecución: `succeeded`, `failed` o `interrupted` (detenida por la persona, igualmente cobrada).

**filters\[execution\_type]\[]** `array of string`

Valores exactos de tipo de ejecución, tal como aparecen en una respuesta agrupada anterior (por ejemplo `chat`, `text`, `image`, `tool_execution`).

**filters\[charge\_type]\[]** `array of string`

Valores exactos de tipo de cobro (por ejemplo `execution`).

**filters\[execution\_origin]\[]** `array of string`

Valores exactos de origen de la ejecución.

**compare** `string`

`previous_period` (mismo número de días, justo antes del periodo) o `previous_calendar_month` (los meses naturales anteriores completos, como máximo 3). Añade `comparison` a la respuesta y a cada grupo.

**sort** `string`

Id de la métrica por la que se ordenan los grupos. Por defecto: la primera métrica solicitada.

**sort\_by** `string`

`value` (por defecto), `delta_abs` o `delta_pct` (variación respecto al periodo de comparación; ambos requieren `compare`).

**order** `string`

`desc` (por defecto) o `asc`. Los valores nulos siempre van al final.

**limit** `integer`

Grupos por página. Por defecto 50, máximo 200.

**cursor** `string`

Cursor opaco de la página siguiente (`page.next_cursor` de una respuesta anterior).

**include\_group\_series** `boolean`

Devuelve también la serie de cada grupo.

**Parámetros en array**

Envía claves repetidas con corchetes, exactamente como se muestra: `group_by[]=resource&filters[person][]=me&filters[person][]=my_team`. Los filtros solo acotan los datos; un valor fuera de tu alcance se rechaza, nunca se descarta en silencio.

**IDs: nunca los inventes**

* Los ids de equipos vienen solo de `scope.teams` de una respuesta (`scope.teams_total` es el recuento sin recorte).
* Los ids de agentes, personas y recursos vienen de `groups[].dimensions.<dimensión>.id` de una respuesta anterior agrupada por esa dimensión.
* Los conjuntos cerrados (`modality`, `activity_category`, `agent_origin`, `trigger_source`, `resource_kind`, `status`) están listados arriba; los valores abiertos (`execution_type`, `charge_type`, `execution_origin`) vienen de una respuesta agrupada anterior.

**Recursos y totales no aditivos**

Agrupar o filtrar por `resource`, `resource_kind` o `charge_type` cuenta las ejecuciones que **usaron** cada recurso. Una ejecución que usó dos tools cuenta una vez en cada grupo, así que entre recursos los totales de las métricas de ejecución (`executions`, `failed_executions`, `success_rate`, `avg_credits_per_execution`) vuelven como `null` y `meta.non_additive` indica cuáles: lee los valores por grupo, nunca sumes los grupos. Los créditos y `uses` siempre suman. Los alcances solo de modelo (`filters[resource_kind][]=model`) siguen siendo exactos.

### **Respuesta**

```json theme={null}
{
  "data": {
    "workspace_id": 4645,
    "scope": {
      "level": "workspace",
      "can_view_person_data": true,
      "can_view_cost": true,
      "downgrade_reason": null,
      "teams": [],
      "teams_total": 0
    },
    "period": {
      "from": "2026-10-01",
      "to": "2026-10-28",
      "timezone": "America/Sao_Paulo",
      "days": 28,
      "granularity": "month",
      "starts_at": "2026-10-01T03:00:00Z",
      "ends_at": "2026-10-29T03:00:00Z"
    },
    "metrics": {
      "consumption_net": {
        "id": "consumption_net",
        "name": "Net consumption",
        "unit": "credits",
        "aggregation": "sum",
        "max_window_days": 93
      }
    },
    "totals": {
      "consumption_net": 22.44224,
      "consumption_charged": 22.44224,
      "consumption_refunded": 0
    },
    "series_metrics": ["consumption_net", "consumption_charged", "consumption_refunded"],
    "series": [
      {
        "bucket": "2026-10-01",
        "starts_at": "2026-10-01T03:00:00Z",
        "ends_at": "2026-10-29T03:00:00Z",
        "complete": false,
        "values": {
          "consumption_net": 22.44224,
          "consumption_charged": 22.44224,
          "consumption_refunded": 0
        }
      }
    ],
    "dimensions": {
      "group_by": ["resource"],
      "filters": { "resource_kind": ["model"] },
      "resolved_filters": {}
    },
    "groups": [
      {
        "key": "[\"model:claude-fable-5.1\"]",
        "dimensions": {
          "resource": {
            "id": "model:claude-fable-5.1",
            "kind": "model",
            "name": "claude-fable-5.1",
            "label": "claude-fable-5.1",
            "kind_label": "AI model"
          }
        },
        "totals": {
          "consumption_net": 19.908,
          "consumption_charged": 19.908,
          "consumption_refunded": 0
        },
        "share": {
          "consumption_net": 0.887077,
          "consumption_charged": 0.887077,
          "consumption_refunded": null
        }
      }
    ],
    "page": {
      "limit": 5,
      "sort": "consumption_net",
      "sort_by": "value",
      "order": "desc",
      "total_groups": 6,
      "has_more": true,
      "next_cursor": "eyJmIjoi..."
    },
    "freshness": {
      "data_available_from": "2026-09-28T00:00:00Z",
      "data_as_of": "2026-10-28T19:50:00Z",
      "partial": false
    },
    "comparison": {
      "type": "previous_period",
      "period": { "from": "2026-09-03", "to": "2026-09-30", "days": 28 },
      "available": false,
      "reason": "period_before_coverage"
    },
    "meta": {
      "catalog_version": 6,
      "resource_scoped": true,
      "non_additive": {},
      "notes": [],
      "limits": {
        "max_window_days": 93,
        "max_group_by": 3,
        "max_filter_values": 100,
        "default_page_size": 50,
        "max_page_size": 200
      }
    }
  }
}
```

### **Campos de la respuesta**

| **Campo** | **Descripción** |
| :- | :- |
| scope | Lo que puedes leer: `level` (`own`, `team` o `workspace`), `can_view_person_data`, `can_view_cost`, `teams` (los ids que acepta `filters[team][]`, con `mine` marcando tus equipos) y `teams_total`. `downgrade_reason` dice por qué el nivel es más restringido de lo que pidió tu rol (`null` en caso contrario). |
| period | El periodo solicitado, ya resuelto: fechas locales, zona horaria, número de días, granularidad e instantes en UTC. |
| metrics | Definición de cada métrica devuelta: id, nombre, definición, unidad, agregación, ventana máxima y comparaciones admitidas. Los detalles internos del rollup no forman parte del contrato público. |
| totals | Valor de cada métrica en el periodo completo. `null` cuando la métrica no es aditiva entre los recursos pedidos (ver `meta.non_additive`). |
| series | Un bucket por paso de granularidad, rellenado con ceros; `complete` es `false` en el bucket todavía en curso. |
| series\_metrics | Los ids de las métricas que lleva cada entrada de `series[].values`, en orden. |
| dimensions | Eco de `group_by` y `filters`; `resolved_filters.person` muestra cómo se resolvieron los alias de persona (`aliases`, `resolved_count` y `user_ids` solo con permiso de datos por persona). |
| groups | Con `group_by`: una entrada por grupo con `dimensions` (siempre con el id para reutilizarlo como filtro), `totals`, `share` (parte del total del periodo, solo métricas aditivas) y, con `compare`, `comparison` y `change_abs`. |
| page | `limit`, `sort`, `sort_by`, `order`, `total_groups`, `has_more` y `next_cursor` para la página siguiente. |
| freshness | `data_available_from` (primer día con datos), `data_as_of` (actualidad de los datos) y `partial` (`true` mientras el periodo incluya horas aún no procesadas). |
| comparison | Con `compare`: el periodo de comparación, `available`, totales, `delta` y, para `consumption_net` y `executions`, una `decomposition` en efecto personas y efecto intensidad. `reason` explica una comparación no disponible. |
| meta | `catalog_version`, `non_additive`, `notes` (por ejemplo `small_group` en un agregado `my_team` pequeño) y los `limits` fijos. |

### **Errores**

Los rechazos de la consulta son objetos JSON con un `code` estable. Los fallos de validación de la solicitud (un `granularity`, `compare`, `sort_by` u `order` desconocido, una fecha mal formada) vuelven como 422 en el formato `{message, errors}` de Laravel; los rechazos de acceso (403/404) traen solo `message`:

```json theme={null}
{
  "message": "The period is too long for the requested metrics.",
  "type": "error",
  "status": 422,
  "code": "window_too_large",
  "details": { "max_window_days": 93, "requested_days": 120 }
}
```

| **Status** | **Code** | **Cuándo** |
| :- | :- | :- |
| 401 | | Token ausente o inválido. |
| 403 | | Sin acceso a la API en el workspace, no miembro, Mission Control deshabilitado o sin `mission-control:view`. Solo `message`, sin `code`; la misma respuesta en todos los casos. |
| 404 | | El workspace de `x-workspace-id` no existe. |
| 403 | `person_data_not_allowed` | `group_by[]=person` o ids de personas sin `mission-control:person-data:view`. Usa `filters[person][]=me` o `my_team`. |
| 403 | `filter_outside_scope` | Id de persona o equipo fuera de tu alcance. |
| 422 | `window_too_large`, `period_before_coverage`, `invalid_period`, `invalid_timezone`, `unsupported_timezone`, `unknown_metric`, `metric_not_queryable`, `unsupported_dimension`, `unsupported_filter`, `invalid_filter`, `invalid_sort`, `invalid_cursor`, `no_team`, `invalid_page_size`, `too_many_dimensions`, `too_many_groups`, `row_limit_exceeded` | Consulta inválida o demasiado grande; `details` trae el límite o el valor ofensivo. `no_team`: `my_team` sin equipo activo. |
| 503 | `usage_rollup_disabled`, `data_not_ready` | Datos de uso aún no disponibles: para este workspace (`usage_rollup_disabled`, `details.reason`: `workspace_not_enabled` o `workspace_backfill_pending`; `details` vacío (sin `details.reason`) cuando los datos de uso están desactivados para todos los workspaces) o en general (`data_not_ready`, el historial de uso aún no se ha construido). Inténtalo más tarde; la respuesta nunca son ceros. |


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