# Puntos de control

A **punto de control** pide la aprobación de una acción de un solo agente. Usted crea uno antes de que la acción se ejecuta; Maetra lo evalúa contra su activo [políticas](https://maetra.io/es/docs/govern-api/policies) y devuelve una decisión - inmediatamente para resultados rápidos, o después de que un humano responda.

### Ciclo de vida

```
create ─▶ evaluate ─┬─▶ approved / rejected / blocked   (terminal, signed)
                    └─▶ pending ─▶ (human decides) ─▶ approved / rejected
                                └─▶ (timeout)      ─▶ expired
```

| Situación | Significado |
| ----------- | ------------------------------------------------ |
| `pending` | Esperando una decisión humana. Contaminación del resultado. |
| `approved` | Autorizado. A `decision_token` se publica. |
| `rejected` | Un revisor se negó. |
| `blocked` | Una política lo bloqueó automáticamente (no se necesita humano). |
| `expired` | No hay decisión antes del tiempo libre. |
| `cancelled` | Cancelado antes de la resolución. |

Sólo `approved` las decisiones pueden seguir autorizando la ejecución de un solo uso.

### Crear un puesto de control

`POST /v1/checkpoints` - Requiere el alcance `govern:checkpoints:write`.

Evaluado sincrónicamente: una política de ayuno puede devolver una decisión terminal en la misma respuesta; de lo contrario se obtiene una `pending` punto de control a la encuesta.

#### Exact policies and decision intelligence

`/v1/checkpoints` utiliza las políticas activas configuradas en Govern. Una política puede usar condiciones exactas salvadas, o puede usar **Inteligencia de decisión del agente de inteligencia** para evaluar el riesgo de tiempo de ejecución.

Tú sí. **no** enviar un mensaje `decision_intelligence` bandera en la solicitud de control. Permitir la inteligencia de decisión sobre la política en el tablero de mando. La llamada API se mantiene igual; Maetra aplica el modo de política y devuelve la misma forma de decisión de control.

**Solicitud de cuerpo**

| Campo | Tipo | Necesario | Descripción |
| ------------------ | --------- | -------- | ------------------------------------------------------------ |
| `action` | cuerda. | ✓ | El nombre de la acción, por ejemplo. `transfer_funds`. |
| `payload` | objeto || Detalles estructurados de la acción. |
| `agent_name` | cuerda. || Llamador legible por humanos (utilizado cuando el agente no está registrado). |
| `agent_id` | cuerda. || ID de agente registrado (ver [Agentes](https://maetra.io/es/docs/agents)). |
| `context` | cuerda. || Contexto libre para los revisores. |
| `reasoning` | cuerda. || El agente está razonando. |
| `autonomy_level` | cuerda. || Nivel de autonomía de agente, `L0`–`L5`. |
| `policy_ids` | string\[] || Restrict evaluation to these exact or decision-intelligence policies. |
| `policy_group_ids` | string\[] || Restrict evaluation to these policy groups. |
| `timeout_seconds` | entero || El techo de las 24 horas para una decisión humana. |
| `target` | objeto || Cuenta, recurso o proveedor la acción afectará. |
| `task_authorization` | objeto || Identificación de tareas, revisión y acción externa que autorizó el trabajo. |
| `runtime` | objeto || Herramientas y modelos de nombres y versiones utilizadas para proponer la acción. |
| `executor_audience` | cuerda. || El servicio permite consumir la capacidad aprobada. |

#### cURL

```bash
curl -X POST "https://api.maetra.io/v1/checkpoints" \
  -H "Authorization: Bearer $MAETRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "delete_customer",
  "agent_name": "ops-agent",
  "payload": {
    "customer_id": "cus_41ab"
  },
  "reasoning": "GDPR erasure request #8821."
}'
```

#### JavaScript

```javascript
const res = await fetch("https://api.maetra.io/v1/checkpoints", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
      "action": "delete_customer",
      "agent_name": "ops-agent",
      "payload": {
          "customer_id": "cus_41ab"
      },
      "reasoning": "GDPR erasure request #8821."
  }),
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = await res.json();
console.log(data);
```

#### TypeScript

```typescript
interface CheckpointDecision {
  checkpoint_id: string;
  status: string;
  decision_token: string | null;
  expires_at: string | null;
  evals: unknown[];
}

const res = await fetch("https://api.maetra.io/v1/checkpoints", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
      "action": "delete_customer",
      "agent_name": "ops-agent",
      "payload": {
          "customer_id": "cus_41ab"
      },
      "reasoning": "GDPR erasure request #8821."
  }),
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = (await res.json()) as CheckpointDecision;
```

#### Python

```python
import os, requests

res = requests.post(
    "https://api.maetra.io/v1/checkpoints",
    headers={"Authorization": f"Bearer {os.environ['MAETRA_API_KEY']}"},
    json={
        "action": "delete_customer",
        "agent_name": "ops-agent",
        "payload": {
            "customer_id": "cus_41ab"
        },
        "reasoning": "GDPR erasure request #8821."
    },
)
res.raise_for_status()
print(res.json())
```

#### Rust

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key = std::env::var("MAETRA_API_KEY")?;
    let client = reqwest::Client::new();
    let res = client
        .post("https://api.maetra.io/v1/checkpoints")
        .bearer_auth(&key)
        .json(&json!({
            "action": "delete_customer",
            "agent_name": "ops-agent",
            "payload": {
                "customer_id": "cus_41ab"
            },
            "reasoning": "GDPR erasure request #8821."
        }))
        .send()
        .await?;
    let data: serde_json::Value = res.json().await?;
    println!("{data:#}");
    Ok(())
}
```

#### C++

```cpp
#include <curl/curl.h>
#include <cstdlib>
#include <string>

int main() {
    CURL* curl = curl_easy_init();
    std::string auth = "Authorization: Bearer " + std::string(std::getenv("MAETRA_API_KEY"));
    struct curl_slist* headers = nullptr;
    headers = curl_slist_append(headers, auth.c_str());
    headers = curl_slist_append(headers, "Content-Type: application/json");
    curl_easy_setopt(curl, CURLOPT_URL, "https://api.maetra.io/v1/checkpoints");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, R"({  "action": "delete_customer",  "agent_name": "ops-agent",  "payload": {    "customer_id": "cus_41ab"  },  "reasoning": "GDPR erasure request #8821."})");
    curl_easy_perform(curl);   // response is written to stdout by default
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}
```

#### Java

```java
import java.net.URI;
import java.net.http.*;

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.maetra.io/v1/checkpoints"))
    .header("Authorization", "Bearer " + System.getenv("MAETRA_API_KEY"))
    .header("Content-Type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
{
  "action": "delete_customer",
  "agent_name": "ops-agent",
  "payload": {
    "customer_id": "cus_41ab"
  },
  "reasoning": "GDPR erasure request #8821."
}"""))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```


#### Con un agente registrado

La llamada anterior utiliza `agent_name` porque el agente no está registrado — el caso común. Si el agente **es** [registrados](https://maetra.io/es/docs/agents), pasar su `agent_id` en su lugar (o al lado) `agent_name`) por lo que el puesto de control se atribuye a él:

```json
{
  "action": "delete_customer",
  "agent_id": "agt_5Ab2",
  "payload": { "customer_id": "cus_41ab" },
  "reasoning": "GDPR erasure request #8821."
}
```

#### Alcance de políticas con identidad de agente opcional

`agent_id` es opcional para `/v1/checkpoints`. Cuando envías sólo `agent_name`Govern todavía evalúa la acción.

Para la evaluación automática de políticas activas:

| Solicitud de identidad | Políticas consideradas |
| ------------------------------------ | --------------------------------------------------------------------------------------------- |
| Registrado `agent_id` | Políticas para toda la organización, además de políticas asignadas a ese agente registrado. |
| `agent_name` coincide con un agente registrado | Políticas para toda la organización, además de políticas asignadas a ese agente registrado. |
| Desconocido o no registrado `agent_name` | Políticas para toda la Organización solamente. Las políticas específicas del agente no se ejecutan accidentalmente. |
| No hay identidad de agente | Políticas para toda la Organización solamente. |

Uso `agent_id` para la atribución estable. Uso `agent_name` sólo para los agentes de API o MCP que aún no se han registrado. Si pasas `policy_ids` o `policy_group_ids`, Maetra evalúa esa selección explícita. La selección puede incluir políticas exactas o políticas de inteligencia de decisiones.

#### Respuesta

```json
{
  "checkpoint_id": "cp_7Yh2Qa",
  "agent_id": null,
  "agent_name": "ops-agent",
  "status": "pending",
  "reason": null,
  "decision_token": null,
  "expires_at": "2026-07-07T12:05:00.000Z",
  "evals": [
    { "policy_name": "Destructive actions", "status": "pending", "quorum_required": 2, "quorum_met": 0, "pool_size": 4 }
  ]
}
```

| Campo | Tipo | Descripción |
| ------------------------- | -------------- | ----------------------------------------------------------------------------------------------- |
| `checkpoint_id` | cuerda. | La identificación del puesto de control. |
| `agent_id` / `agent_name` | cuerda. \| nulo | La identidad de llamada que proveiste. |
| `status` | enum | `pending`, `approved`, `rejected`, `expired`, `blocked`, `cancelled`. |
| `reason` | cuerda. \| nulo | Razón humana o política, cuando esté disponible. |
| `decision_token` | cuerda. \| nulo | Signed JWT proving a terminal decision - ver [Decision tokens](https://maetra.io/es/docs/govern-api/decision-tokens). |
| `action_envelope` / `action_envelope_hash` | objeto / cadena | Exact proposal and canonical SHA-256 binding. |
| `policy_versions` / `policy_digest` | array / cadena | Exact policy versions used for the decision. |
| `decision_token_expires_at` | cuerda. \| nulo | Gastos de la capacidad de decisión firmada de un uso único. |
| `execution_expected_at` / `effect_expected_at` | cuerda. \| nulo | Los letreros solían aparecer evidencias de ciclo de vida perdido. |
| `expires_at` | cuerda. \| nulo | Caducidad ISO 8601. |
| `evals` | array | Detalle de evaluación por políticas (bajo). |

**Objeto Eval:** `policy_id`, `policy_name`, `applicability`, `status`, `quorum_required`, `quorum_met`, `pool_size`.

### Obtenga un puesto de control (solución fría)

`GET /v1/checkpoints/{id}` - alcance `govern:checkpoints:read`. Devuelve el estado actual sin esperar. Mantenga ≥1 segundo entre las encuestas del mismo punto de control; prefiera el largo-poll abajo.

#### cURL

```bash
curl "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa" \
  -H "Authorization: Bearer $MAETRA_API_KEY"
```

#### JavaScript

```javascript
const res = await fetch("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
  },
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = await res.json();
console.log(data);
```

#### TypeScript

```typescript
const res = await fetch("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
  },
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = (await res.json());
```

#### Python

```python
import os, requests

res = requests.get(
    "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa",
    headers={"Authorization": f"Bearer {os.environ['MAETRA_API_KEY']}"},
)
res.raise_for_status()
print(res.json())
```

#### Rust

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key = std::env::var("MAETRA_API_KEY")?;
    let client = reqwest::Client::new();
    let res = client
        .get("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa")
        .bearer_auth(&key)
        .send()
        .await?;
    let data: serde_json::Value = res.json().await?;
    println!("{data:#}");
    Ok(())
}
```

#### C++

```cpp
#include <curl/curl.h>
#include <cstdlib>
#include <string>

int main() {
    CURL* curl = curl_easy_init();
    std::string auth = "Authorization: Bearer " + std::string(std::getenv("MAETRA_API_KEY"));
    struct curl_slist* headers = nullptr;
    headers = curl_slist_append(headers, auth.c_str());
    curl_easy_setopt(curl, CURLOPT_URL, "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_perform(curl);   // response is written to stdout by default
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}
```

#### Java

```java
import java.net.URI;
import java.net.http.*;

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa"))
    .header("Authorization", "Bearer " + System.getenv("MAETRA_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```


### Esperar una decisión (pola larga)

`GET /v1/checkpoints/{id}/wait` - alcance `govern:checkpoints:read`. Mantiene la conexión abierta hasta que el punto de control cambie de estado o el detenimiento salta. La manera eficiente de esperar a un humano.

* Query `timeout`- Esperen segundos. `1`–`55` (default) `50`).
* `200` - cambiado; el cuerpo es el nuevo estado. `202` - sin cambio; reconectar.

#### cURL

```bash
curl "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50" \
  -H "Authorization: Bearer $MAETRA_API_KEY"
```

#### JavaScript

```javascript
const res = await fetch("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
  },
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = await res.json();
console.log(data);
```

#### TypeScript

```typescript
const res = await fetch("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.MAETRA_API_KEY}`,
  },
});
if (!res.ok) throw new Error(`Maetra API ${res.status}`);
const data = (await res.json());
```

#### Python

```python
import os, requests

res = requests.get(
    "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50",
    headers={"Authorization": f"Bearer {os.environ['MAETRA_API_KEY']}"},
)
res.raise_for_status()
print(res.json())
```

#### Rust

```rust
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key = std::env::var("MAETRA_API_KEY")?;
    let client = reqwest::Client::new();
    let res = client
        .get("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50")
        .bearer_auth(&key)
        .send()
        .await?;
    let data: serde_json::Value = res.json().await?;
    println!("{data:#}");
    Ok(())
}
```

#### C++

```cpp
#include <curl/curl.h>
#include <cstdlib>
#include <string>

int main() {
    CURL* curl = curl_easy_init();
    std::string auth = "Authorization: Bearer " + std::string(std::getenv("MAETRA_API_KEY"));
    struct curl_slist* headers = nullptr;
    headers = curl_slist_append(headers, auth.c_str());
    curl_easy_setopt(curl, CURLOPT_URL, "https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_perform(curl);   // response is written to stdout by default
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    return 0;
}
```

#### Java

```java
import java.net.URI;
import java.net.http.*;

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.maetra.io/v1/checkpoints/cp_7Yh2Qa/wait?timeout=50"))
    .header("Authorization", "Bearer " + System.getenv("MAETRA_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```


### Flujo recomendado

1. `POST /v1/checkpoints`.
2. Si. `status` ya es terminal, actuar en él (y verificar el token).
3. Si. `pending`, largo-poll `/wait` hasta la terminal.
4. Encendida `approved`, [verificar la decisión token](https://maetra.io/es/docs/govern-api/decision-tokens),
entonces consumirlo a través [autorización de ejecución](https://maetra.io/es/docs/govern-api/execution-receipts) inmediatamente antes de actuar. Grabar cada intento y verificar el efecto. En cualquier otra cosa, no actúes.