{
  "openapi": "3.1.0",
  "info": {
    "title": "Kobana Autonomous Inbox API",
    "version": "1.2.0",
    "description": "API REST pública para el Inbox Autónomo de Kobana.\n\nAutenticación: Bearer JWT (RS256, emitido por el Authorization Server de Kobana; `aud` incluye `https://api.inbox[.<env>].kobana.com.br`) más mTLS terminado en CloudFront (transmitido mediante el header `cloudfront-viewer-mtls-client-cert-fingerprint`). El claim `org` del JWT (la cuenta Kobana) resuelve la organización del llamador; `sub` es la persona y se lleva solo para atribución. Elige un workspace dentro de la organización con `X-Workspace-Id` cuando haya más de uno.\n\nLos endpoints de recursos `{id}` (workspaces, inboxes, agents, webhooks) aceptan tanto el UUID interno como el `external_id` del recurso. Los endpoints POST que poseen un `external_id` lo aceptan como campo opcional y, si se omite, usan por defecto el `id` interno generado. El campo `deleted_at` nunca se devuelve en las respuestas ni en los payloads de webhook; los registros con soft-delete se filtran en su lugar.\n\nTodas las claves en las respuestas y en los payloads de webhook están en `snake_case`. Las entregas de webhook comparten el serializador de la API: el envelope trae `event` (`slug`, `id`), `delivered_at` y `workspace`; `data` anida snapshots de los recursos (`organization`, `agent`, `inbox`, `email`, `agent_run`) más las claves específicas del evento."
  },
  "servers": [
    {
      "url": "https://api.inbox.kobana.com.br",
      "description": "Producción"
    },
    {
      "url": "https://api.inbox.sandbox.kobana.com.br",
      "description": "Sandbox"
    },
    {
      "url": "http://localhost:3028/api",
      "description": "Desarrollo local"
    }
  ],
  "tags": [
    {
      "name": "Workspaces"
    },
    {
      "name": "Inboxes"
    },
    {
      "name": "Emails"
    },
    {
      "name": "Agents"
    },
    {
      "name": "Agent runs"
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Webhook deliveries"
    },
    {
      "name": "System events"
    },
    {
      "name": "Secrets"
    },
    {
      "name": "Workflow runs"
    },
    {
      "name": "Usage"
    },
    {
      "name": "LLM models"
    },
    {
      "name": "Identity"
    }
  ],
  "paths": {
    "/v1/workspaces": {
      "get": {
        "operationId": "list-workspaces",
        "summary": "Listar Workspaces",
        "description": "Alcance: la organización del workspace del token — todo workspace vivo de esa organización es alcanzable; uno fuera de ella es 404. Un token cuyo workspace no tiene organización solo se ve a sí mismo. Paginación keyset con filtros tipados.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workspaces"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `label`, `slug`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `source[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `slug[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `external_id[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `updated_at[in]=a,b` y `updated_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Workspace"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-workspace",
        "summary": "Crear Workspace",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workspaces",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkspaceCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "Requiere un token `src=system`. El workspace se crea dentro de la organización del token. Alcance: la organización del workspace del token — todo workspace vivo de esa organización es alcanzable; uno fuera de ella es 404. Un token cuyo workspace no tiene organización solo se ve a sí mismo."
      },
      "put": {
        "operationId": "upsert-workspace",
        "summary": "Crear o actualizar workspace",
        "description": "Upsert. Recibe el mismo cuerpo que POST más las claves de búsqueda `id` y `external_id`, comparadas en ese orden. Una coincidencia se actualiza in situ y devuelve 200 — los campos ausentes del cuerpo conservan el valor almacenado. Sin clave, o sin coincidencia, crea el workspace exactamente como lo haría POST y devuelve 201. Alcance: la organización del workspace del token — todo workspace vivo de esa organización es alcanzable; uno fuera de ella es 404. Un token cuyo workspace no tiene organización solo se ve a sí mismo. Requiere un token `src=system`; `external_id` no puede cambiarse en un workspace coincidente (409).",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workspaces",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkspaceUpsert"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{id}": {
      "get": {
        "operationId": "get-workspace",
        "summary": "Obtener Workspace",
        "description": "Acepta el UUID interno o el `external_id` del recurso. Alcance: la organización del workspace del token — todo workspace vivo de esa organización es alcanzable; uno fuera de ella es 404. Un token cuyo workspace no tiene organización solo se ve a sí mismo.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workspaces"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-workspace",
        "summary": "Actualizar Workspace",
        "description": "Acepta el UUID interno o el `external_id` del recurso. Alcance: la organización del workspace del token — todo workspace vivo de esa organización es alcanzable; uno fuera de ella es 404. Un token cuyo workspace no tiene organización solo se ve a sí mismo. Cambiar `monthly_cost_limit` / `monthly_emails_limit` requiere un token `src=system`.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workspaces",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WorkspaceUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-workspace",
        "summary": "Eliminar Workspace",
        "description": "Acepta el UUID interno o el `external_id` del recurso. Alcance: la organización del workspace del token — todo workspace vivo de esa organización es alcanzable; uno fuera de ella es 404. Un token cuyo workspace no tiene organización solo se ve a sí mismo. Requiere un token `src=system`.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workspaces",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Sin contenido."
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/inboxes": {
      "get": {
        "operationId": "list-inboxes",
        "summary": "Listar Inboxes",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `label`, `slug`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `status[in]=a,b`.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "inactive"
              ]
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `agent_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `slug[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `email[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `external_id[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `updated_at[in]=a,b` y `updated_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Inbox"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-inbox",
        "summary": "Crear Inbox",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboxCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Inbox"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsert-inbox",
        "summary": "Crear o actualizar buzón",
        "description": "Upsert. Recibe el mismo cuerpo que POST más las claves de búsqueda `id` y `external_id`, comparadas en ese orden, luego por `email`. Una coincidencia se actualiza in situ y devuelve 200 — los campos ausentes del cuerpo conservan el valor almacenado. Sin clave, o sin coincidencia, crea el buzón exactamente como lo haría POST y devuelve 201.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboxUpsert"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Inbox"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Inbox"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/inboxes/{id}": {
      "get": {
        "operationId": "get-inbox",
        "summary": "Obtener Inbox",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Inbox"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-inbox",
        "summary": "Actualizar Inbox",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboxUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Inbox"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-inbox",
        "summary": "Eliminar Inbox",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Sin contenido."
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/agents": {
      "get": {
        "operationId": "list-agents",
        "summary": "Listar Agents",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `label`, `version`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "llm_model",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `llm_model[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `external_id[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `updated_at[in]=a,b` y `updated_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Agent"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-agent",
        "summary": "Crear Agent",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsert-agent",
        "summary": "Crear o actualizar agente",
        "description": "Upsert. Recibe el mismo cuerpo que POST más las claves de búsqueda `id` y `external_id`, comparadas en ese orden. Una coincidencia se actualiza in situ y devuelve 200 — los campos ausentes del cuerpo conservan el valor almacenado. Sin clave, o sin coincidencia, crea el agente exactamente como lo haría POST y devuelve 201.",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentUpsert"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/agents/{id}": {
      "get": {
        "operationId": "get-agent",
        "summary": "Obtener Agent",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-agent",
        "summary": "Actualizar Agent",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-agent",
        "summary": "Eliminar Agent",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Sin contenido."
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks": {
      "get": {
        "operationId": "list-webhooks",
        "summary": "Listar Webhooks",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `label`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `status[in]=a,b`.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "inactive"
              ]
            }
          },
          {
            "name": "inbox_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `inbox_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `external_id[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `updated_at[in]=a,b` y `updated_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-webhook",
        "summary": "Crear Webhook",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsert-webhook",
        "summary": "Crear o actualizar webhook",
        "description": "Upsert. Recibe el mismo cuerpo que POST más las claves de búsqueda `id` y `external_id`, comparadas en ese orden. Una coincidencia se actualiza in situ y devuelve 200 — los campos ausentes del cuerpo conservan el valor almacenado. Sin clave, o sin coincidencia, crea el webhook exactamente como lo haría POST y devuelve 201.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpsert"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}": {
      "get": {
        "operationId": "get-webhook",
        "summary": "Obtener Webhook",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-webhook",
        "summary": "Actualizar Webhook",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-webhook",
        "summary": "Eliminar Webhook",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Sin contenido."
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/secrets": {
      "get": {
        "operationId": "list-secrets",
        "summary": "Listar secrets",
        "description": "Paginación por keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`). El valor de un secret nunca lo devuelve ningún endpoint: se guarda cifrado y solo lo lee el ejecutor de workflows. Para rotarlo, haga `PATCH` sobre la fila (o `PUT` por `key`) con un nuevo `value`.",
        "tags": [
          "Secrets"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/secrets"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `label`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "key",
            "in": "query",
            "required": false,
            "description": "Equality. Also `key[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `updated_at[in]=a,b` y `updated_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Secret"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Opaque keyset cursor for the next page; `null` on the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-secret",
        "summary": "Crear secret",
        "tags": [
          "Secrets"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/secrets",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SecretCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Secret"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "Guarda un secret que un workflow del agente puede referenciar como `${{secrets.KEY}}`. Una `key` duplicada en el workspace se rechaza con 409 `conflict`. El valor es de solo escritura: se guarda cifrado y nunca se devuelve."
      },
      "put": {
        "operationId": "upsert-secret",
        "summary": "Crear o actualizar secret",
        "description": "Upsert emparejado por `key` dentro del workspace de quien llama — el camino de la rotación, sin buscar el id. Crea con 201 cuando la clave es nueva, reemplaza el valor con 200 cuando ya existe. El valor es de solo escritura.",
        "tags": [
          "Secrets"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/secrets",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SecretUpsert"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Secret"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Secret"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/secrets/{id}": {
      "get": {
        "operationId": "get-secret",
        "summary": "Obtener secret",
        "description": "Accepts either the internal UUID or the resource `external_id`.",
        "tags": [
          "Secrets"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/secrets"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Secret"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-secret",
        "summary": "Actualizar secret",
        "description": "Reemplaza el valor o las notas. `key` es inmutable: los workflows la referencian por nombre, así que renombrarla los rompería en silencio — elimine y cree de nuevo.",
        "tags": [
          "Secrets"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/secrets",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SecretUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Secret"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Se violó una restricción de unicidad (por ejemplo, `external_id` o el `email` del inbox ya en uso).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validación del cuerpo que requiere contexto del lado del servidor (por ejemplo, dominio del inbox no coincide).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-secret",
        "summary": "Eliminar secret",
        "description": "Borrado lógico. Los pasos de workflow que referencian la clave empiezan a fallar con `secret not defined` desde la siguiente ejecución.",
        "tags": [
          "Secrets"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/secrets",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workflow-runs": {
      "get": {
        "operationId": "list-workflow-runs",
        "summary": "Listar ejecuciones de workflow",
        "description": "Paginación por keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`). Los pasos no vienen incluidos en el listado — `GET /v1/workflow-runs/{id}` los devuelve.",
        "tags": [
          "Workflow runs"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workflow_runs"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `label`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `status[in]=a,b`.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "running",
                "success",
                "failed"
              ]
            }
          },
          {
            "name": "email_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `email_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "inbox_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `inbox_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `agent_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "agent_run_id",
            "in": "query",
            "required": false,
            "description": "Equality. Also `agent_run_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "finished_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `finished_at[in]=a,b` y `finished_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "finished_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "finished_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page of results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WorkflowRun"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Opaque keyset cursor for the next page; `null` on the last page."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workflow-runs/{id}": {
      "get": {
        "operationId": "get-workflow-run",
        "summary": "Obtener ejecución de workflow",
        "description": "La ejecución con todos sus pasos en orden. Peticiones y respuestas se guardan con los valores de secrets reemplazados por `[REDACTED]`; los cuerpos se truncan a 4000 caracteres.",
        "tags": [
          "Workflow runs"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/workflow_runs"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/WorkflowRun"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails": {
      "get": {
        "operationId": "list-emails",
        "summary": "Listar Emails",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/emails"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `from`, `status`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `status[in]=a,b`.",
            "schema": {
              "type": "string",
              "enum": [
                "received",
                "approved",
                "rejected",
                "processing",
                "processed",
                "failed"
              ]
            }
          },
          {
            "name": "inbox_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `inbox_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `agent_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "message_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `message_id[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `from[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Filas cuyo `to` contiene el valor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `updated_at[in]=a,b` y `updated_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "received_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `received_at[in]=a,b` y `received_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "received_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "received_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "processed_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `processed_at[in]=a,b` y `processed_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "processed_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "processed_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Email"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-email",
        "summary": "Enviar un .eml en bruto",
        "description": "Almacena un mensaje RFC 5322 exactamente como lo haría la ingesta de SES: objeto en bruto en el bucket raw, `Email` en `received` y un job `process-email` — filtros, agente y webhooks se ejecutan como para un correo real. Envía el mensaje como `multipart/form-data` (campo `file`, `inbox_id` opcional) o como cuerpo de la solicitud con `Content-Type: message/rfc822` (`?inbox_id=` opcional). Sin `inbox_id`, el buzón se resuelve a partir del encabezado `To:` entre los buzones del workspace del token. Un `Message-ID` ya almacenado se rechaza con 409 (`error.details.email_id` apunta al correo existente).",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/emails",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "inbox_id",
            "in": "query",
            "required": false,
            "description": "Buzón de destino. Se sobrescribe con el campo multipart `inbox_id` cuando se envían ambos.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "message/rfc822": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "El archivo `.eml` (máx. 20 MB)."
                  },
                  "inbox_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Almacenado y encolado para procesamiento.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "queued"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Email"
                    },
                    "queued": {
                      "type": "boolean",
                      "description": "`false` cuando la fila se almacenó pero el job de procesamiento no pudo encolarse; reprocesa más tarde."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Cuerpo vacío o campo multipart `file` ausente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`inbox_id` no existe en el workspace del token (`inbox_not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`duplicate_message_id`: el `Message-ID` ya está almacenado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: mensaje de más de 20 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: el cuerpo no es multipart ni `message/rfc822`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`no_inbox_matches_to_header` (ningún buzón del workspace coincide con los destinatarios de `To:`) o `missing_recipient` (sin encabezado `To:` utilizable; envía `inbox_id`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{id}": {
      "get": {
        "operationId": "get-email",
        "summary": "Obtener Email",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/emails"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Email"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-email",
        "summary": "Eliminar correo",
        "description": "Soft-delete del correo (establece `deleted_at`). Deja de aparecer en listados y detalle; el objeto en bruto lo purga el job de retención.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/emails",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Sin contenido."
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{id}/eml": {
      "get": {
        "operationId": "download-original-eml",
        "summary": "Descargar el .eml original",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/emails"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Flujo de mensaje RFC 5322 sin procesar.",
            "content": {
              "message/rfc822": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/emails/{id}/reprocess": {
      "post": {
        "operationId": "reprocess-email",
        "summary": "Reprocesar Email",
        "description": "Vuelve a encolar el procesamiento del email sin importar el estado actual.",
        "tags": [
          "Emails"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/emails"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Aceptado y encolado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "email_id",
                        "queued"
                      ],
                      "properties": {
                        "email_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "queued": {
                          "type": "boolean",
                          "enum": [
                            true
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/usage/summary": {
      "get": {
        "operationId": "get-usage-summary",
        "summary": "Resumen de uso",
        "description": "Correos procesados, tokens y costo por día UTC en el rango (solo ejecuciones de agente exitosas), más los contadores mensuales acumulados frente a los límites del workspace. El costo está en USD, según lo factura el AI Gateway.",
        "tags": [
          "Usage"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/usage"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Primer día UTC, `YYYY-MM-DD`. Por defecto, 29 días antes de `to`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Último día UTC (inclusive), `YYYY-MM-DD`. Por defecto, hoy.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UsageSummary"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/usage/cost": {
      "get": {
        "operationId": "get-usage-cost",
        "summary": "Costo por modelo",
        "description": "Costo y tokens por modelo LLM en el rango: totales por modelo y serie diaria.",
        "tags": [
          "Usage"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/usage"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Primer día UTC, `YYYY-MM-DD`. Por defecto, 29 días antes de `to`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Último día UTC (inclusive), `YYYY-MM-DD`. Por defecto, hoy.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/UsageCost"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "operationId": "list-models",
        "summary": "Listar modelos LLM disponibles",
        "description": "Modelos aceptados en `Agent.llm_model`, con precio por token: el catálogo del AI Gateway limitado a los modelos que tienen precio, de modo que todo modelo listado se costea y se cuenta contra el límite del workspace.",
        "tags": [
          "LLM models"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Catálogo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Model"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "`gateway_error`: no se pudo obtener el catálogo del AI Gateway.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/agents/{id}/versions": {
      "get": {
        "operationId": "list-agent-versions",
        "summary": "Listar versiones del prompt del agente",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "Agents"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agents"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `version`. Predeterminado `-version`.",
            "schema": {
              "type": "string",
              "default": "-version"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `version[in]=a,b` y `version[gt|gte|lt|lte]`.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "version[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "version[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentVersion"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/agent-runs": {
      "get": {
        "operationId": "list-agent-runs",
        "summary": "Listar AgentRuns",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "Agent runs"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agent_runs"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `updated_at`, `total_cost`, `status`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `status[in]=a,b`.",
            "schema": {
              "type": "string",
              "enum": [
                "running",
                "success",
                "failed"
              ]
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `agent_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "email_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `email_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "inbox_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `inbox_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "llm_model",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `llm_model[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "finished_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `finished_at[in]=a,b` y `finished_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "finished_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "finished_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "total_cost",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `total_cost[in]=a,b` y `total_cost[gt|gte|lt|lte]`.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "total_cost[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "total_cost[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentRun"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/agent-runs/{id}": {
      "get": {
        "operationId": "get-agent-run",
        "summary": "Obtener AgentRun",
        "tags": [
          "Agent runs"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/agent_runs"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentRun"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/inboxes/{id}/recipients": {
      "post": {
        "operationId": "add-allowed-recipient",
        "summary": "Agregar destinatario permitido",
        "description": "Acepta el UUID interno o el `external_id` del recurso. Agrega un email a `allowed_recipients`. Es idempotente: devuelve 200 con la lista actual cuando ya está presente.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El destinatario ya estaba presente (no-op).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "allowed_recipients": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "format": "email"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Destinatario agregado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "allowed_recipients": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "format": "email"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "remove-allowed-recipient",
        "summary": "Eliminar destinatario permitido",
        "description": "Acepta el UUID interno o el `external_id` del recurso. Elimina un email de `allowed_recipients`. Acepta el email en el cuerpo JSON o como parámetro de consulta `email`.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/inboxes",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "email"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Destinatario eliminado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "allowed_recipients": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "format": "email"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "send-a-webhook-test-event",
        "summary": "Enviar un evento webhook.ping",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Aceptado y encolado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "webhook_id",
                        "event_id",
                        "queued"
                      ],
                      "properties": {
                        "webhook_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "event_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "queued": {
                          "type": "boolean",
                          "enum": [
                            true
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/regenerate-secret": {
      "post": {
        "operationId": "regenerate-the-signing-secret",
        "summary": "Rotar el signing secret",
        "description": "Reemplaza el signing secret y devuelve el nuevo valor **una sola vez**. Por defecto el secret anterior sigue firmando entregas durante 24 horas (`previous_secret_grace_hours`), periodo en el que cada entrega lleva una firma por secret, para que el receptor cambie de clave sin perder eventos. Envía `0` para revocar el secret anterior de inmediato (secret filtrado). Acepta tanto el UUID interno como el `external_id` del recurso.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Opcional. 8-255 caracteres de [A-Za-z0-9_-:.]. Una repetición con la misma clave dentro de 24h devuelve la respuesta original; la misma clave con un cuerpo distinto devuelve 409 `conflict`.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signing_secret": {
                    "type": "string",
                    "pattern": "^whsec_[A-Za-z0-9+/]+={0,2}$",
                    "description": "Opcional. Trae tu propio signing secret: `whsec_` + base64 estándar de 24-64 bytes aleatorios. Se genera (32 bytes) si se omite. Se devuelve en texto claro solo en esta respuesta."
                  },
                  "previous_secret_grace_hours": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 168,
                    "default": 24,
                    "description": "Horas que el secret anterior sigue siendo válido tras la rotación. `0` lo revoca de inmediato."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Nuevo signing secret (se muestra una sola vez).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "signing_secret",
                    "previous_secret_expires_at"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    },
                    "signing_secret": {
                      "type": "string",
                      "example": "whsec_..."
                    },
                    "previous_secret_expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "nullable": true,
                      "description": "Cuándo el secret anterior deja de firmar; `null` si se revocó de inmediato."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "list-webhook-deliveries",
        "summary": "Listar entregas del Webhook",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhook deliveries"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `attempt`, `status`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `status[in]=a,b`.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "success",
                "failed"
              ]
            }
          },
          {
            "name": "attempt",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `attempt[in]=a,b` y `attempt[gt|gte|lt|lte]`.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "attempt[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "attempt[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "response_status",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `response_status[in]=a,b` y `response_status[gt|gte|lt|lte]`.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "response_status[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "response_status[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "system_event_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `system_event_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "delivered_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `delivered_at[in]=a,b` y `delivered_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "delivered_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "delivered_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/deliveries/{deliveryId}": {
      "get": {
        "operationId": "get-webhook-delivery",
        "summary": "Obtener entrega del Webhook",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhook deliveries"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/WebhookDelivery"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/deliveries/{deliveryId}/replay": {
      "post": {
        "operationId": "replay-a-webhook-delivery",
        "summary": "Reproducir una entrega del Webhook",
        "description": "Acepta el UUID interno o el `external_id` del recurso.",
        "tags": [
          "Webhook deliveries"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/webhooks",
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "deliveryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Aceptado y encolado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "required": [
                        "webhook_id",
                        "delivery_id",
                        "system_event_id",
                        "queued"
                      ],
                      "properties": {
                        "webhook_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "delivery_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "system_event_id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "queued": {
                          "type": "boolean",
                          "enum": [
                            true
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/system-events": {
      "get": {
        "operationId": "list-system-events",
        "summary": "Listar SystemEvents",
        "description": "Paginación keyset. Los filtros son query params tipados (`campo=valor`, `campo[op]=valor`); los filtros desconocidos, los campos no ordenables y los valores malformados se rechazan con 400 `validation_failed`.",
        "tags": [
          "System events"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/system_events"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor opaco devuelto en `meta.next_cursor` de la página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Claves de ordenación separadas por coma, prefijo `-` para descendente. Permitidas: `created_at`, `slug`. Predeterminado `-created_at`.",
            "schema": {
              "type": "string",
              "default": "-created_at"
            }
          },
          {
            "name": "slug",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `slug[in]=a,b`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "inbox_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `inbox_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "email_id",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `email_id[in]=a,b`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Igualdad. También `created_at[in]=a,b` y `created_at[gt|gte|lt|lte]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[gte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_at[lte]",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SystemEvent"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "next_cursor"
                      ],
                      "properties": {
                        "next_cursor": {
                          "type": "string",
                          "nullable": true,
                          "description": "Cursor keyset opaco de la página siguiente; `null` en la última página."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "El cuerpo no superó la validación de Zod. `error.details` contiene `formErrors`/`fieldErrors`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/system-events/{id}": {
      "get": {
        "operationId": "get-system-event",
        "summary": "Obtener SystemEvent",
        "tags": [
          "System events"
        ],
        "security": [
          {
            "bearerAuth": [
              "inbox/system_events"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "Fingerprint mTLS. En producción, CloudFront la inyecta a partir del mTLS del viewer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Secreto compartido entre CloudFront y el origin. Obligatorio en producción; se ignora en desarrollo a menos que se configure `CF_ORIGIN_SHARED_SECRET`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Acepta el UUID interno o el `external_id` del recurso.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Éxito.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/SystemEvent"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero el scope es insuficiente o el recurso está fuera de alcance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Recurso no encontrado o excluido por soft-delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "operationId": "get-me",
        "summary": "Identidad detrás del token",
        "description": "A quién representa el token Bearer: la persona (`null` para un token de máquina), la organización y el alcance del propio token. Úsalo para probar si un token configurado es válido. No exige scope de recurso: cualquier token que se verifique recibe respuesta. El token en sí nunca se devuelve.",
        "tags": [
          "Identity"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "cloudfront-viewer-mtls-client-cert-fingerprint",
            "in": "header",
            "required": true,
            "description": "mTLS fingerprint. In production CloudFront injects it from viewer mTLS.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-origin-shared-secret",
            "in": "header",
            "required": false,
            "description": "Shared secret between CloudFront and the origin. Required in production; ignored in development unless `CF_ORIGIN_SHARED_SECRET` is set.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Identidad.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Me"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Fallo de autenticación (JWT o mTLS ausente o inválido).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Autenticado, pero la organización o la membresía del token es desconocida aquí.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "validation_failed"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          }
        }
      },
      "Workspace": {
        "type": "object",
        "description": "Workspace tal como lo devuelve la API. `deleted_at` se omite en las respuestas.",
        "required": [
          "id",
          "external_id",
          "source",
          "label",
          "slug"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "nullable": true
          },
          "source": {
            "$ref": "#/components/schemas/WorkspaceSource"
          },
          "label": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Segmento intermedio de toda dirección de buzón de este workspace: \"{organization-slug}.{workspace-slug}.{inbox-slug}@inbox.kobana.com.br\" (el segmento de la organización se omite cuando el workspace no tiene una). Único dentro de la organización. Por defecto, el label en formato dasherized."
          },
          "monthly_cost_limit": {
            "type": "number",
            "nullable": true
          },
          "monthly_cost_used": {
            "type": "number"
          },
          "monthly_emails_limit": {
            "type": "integer",
            "nullable": true
          },
          "monthly_emails_used": {
            "type": "integer"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del sistema, escritos por Kobana. Solo lectura."
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Escribibles mediante esta API."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WorkspaceSource": {
        "type": "string",
        "enum": [
          "kobana_app",
          "kobana_billing",
          "kobana_inbox",
          "kobana_agent",
          "kobana_finance",
          "kobana_legal",
          "kobana_team"
        ]
      },
      "WorkspaceCreate": {
        "type": "object",
        "required": [
          "source",
          "label"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "description": "Opcional. Cuando se omite, el servidor usa como valor predeterminado de `external_id` el `id` interno generado."
          },
          "source": {
            "$ref": "#/components/schemas/WorkspaceSource"
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
            "description": "Opcional. Slug en minúsculas y dasherized, único dentro de la organización, usado como segmento intermedio de las direcciones de buzón. Limitado a 20 caracteres para que la parte local compuesta quepa en el límite SMTP de 64 caracteres. Si se omite, el servidor lo deriva del `label` dasherized."
          },
          "monthly_cost_limit": {
            "type": "number",
            "nullable": true,
            "exclusiveMinimum": 0
          },
          "monthly_emails_limit": {
            "type": "integer",
            "nullable": true,
            "exclusiveMinimum": 0
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          }
        }
      },
      "WorkspaceUpdate": {
        "type": "object",
        "required": [],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
          },
          "monthly_cost_limit": {
            "type": "number",
            "nullable": true,
            "exclusiveMinimum": 0
          },
          "monthly_emails_limit": {
            "type": "integer",
            "nullable": true,
            "exclusiveMinimum": 0
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          },
          "custom_metadata_mode": {
            "type": "string",
            "enum": [
              "replace",
              "merge"
            ],
            "default": "replace",
            "description": "Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) sobrescribe el objeto completo; `merge` hace deep-merge sobre el valor actual — los objetos anidados se fusionan recursivamente, escalares y arrays sobrescriben la clave, y las claves `null` se conservan (no eliminan la clave). Solo en update."
          }
        }
      },
      "Inbox": {
        "type": "object",
        "required": [
          "id",
          "external_id",
          "workspace_id",
          "label",
          "slug",
          "email",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "nullable": true
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "agent_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "label": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Último segmento de la dirección, único dentro del workspace. Congelado tras la creación: renombrar un slug nunca redirige una dirección ya entregada."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ]
          },
          "allowed_recipients": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "filters": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "attachments_allow": {
            "type": "boolean"
          },
          "attachments_max_file_number": {
            "type": "integer"
          },
          "attachments_max_file_size": {
            "type": "integer"
          },
          "attachments_max_total_size": {
            "type": "integer"
          },
          "attachments_allow_rules": {
            "type": "array",
            "nullable": true,
            "maxItems": 20,
            "description": "Lista de adjuntos permitidos. Un adjunto se procesa cuando cumple al menos una regla; dentro de una regla, todas las condiciones indicadas deben cumplirse. `null` o `[]` procesa todos los adjuntos. Un adjunto fuera de la lista se ignora, nunca es motivo para rechazar el correo: el agente no lo ve, los límites de adjuntos no lo cuentan y un paso de workflow no puede referenciarlo. En la actualización, omítalo para mantener y envíe `null` para limpiar.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "extensions": {
                  "type": "array",
                  "minItems": 1,
                  "maxItems": 50,
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9]{1,16}$"
                  },
                  "description": "Extensiones sin el punto, sin distinguir mayúsculas, p. ej. `[\"pdf\", \"xml\"]`."
                },
                "filename_pattern": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200,
                  "description": "Expresión regular JavaScript evaluada contra el nombre del archivo, p. ej. `^GUIA_`. Los cuantificadores anidados se rechazan. Un adjunto sin nombre nunca cumple."
                },
                "case_sensitive": {
                  "type": "boolean",
                  "description": "Aplica a `filename_pattern`. Por defecto false."
                }
              }
            }
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del sistema, escritos por Kobana. Solo lectura."
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Escribibles mediante esta API."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InboxCreate": {
        "type": "object",
        "required": [
          "label"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "description": "Opcional. Por defecto usa el `id` interno generado."
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Opcional. Debe usar el dominio de buzón configurado (`SES_DOMAIN`); de lo contrario devuelve 422. Las direcciones duplicadas devuelven 409. Si se omite, el servidor la compone como \"{organization-slug}.{workspace-slug}.{inbox-slug}@<domain>\"."
          },
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
            "description": "Opcional. Slug en minúsculas y dasherized, único dentro del workspace, usado como último segmento de la dirección. Devuelve 409 cuando colisiona con otro buzón del mismo workspace y 422 cuando la parte local compuesta supera los 64 caracteres. Si se omite, el servidor lo deriva del `label` dasherized."
          },
          "agent_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "allowed_recipients": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "filters": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "attachments_allow": {
            "type": "boolean"
          },
          "attachments_max_file_number": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "attachments_max_file_size": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "attachments_max_total_size": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "attachments_allow_rules": {
            "type": "array",
            "nullable": true,
            "maxItems": 20,
            "description": "Lista de adjuntos permitidos. Un adjunto se procesa cuando cumple al menos una regla; dentro de una regla, todas las condiciones indicadas deben cumplirse. `null` o `[]` procesa todos los adjuntos. Un adjunto fuera de la lista se ignora, nunca es motivo para rechazar el correo: el agente no lo ve, los límites de adjuntos no lo cuentan y un paso de workflow no puede referenciarlo. En la actualización, omítalo para mantener y envíe `null` para limpiar.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "extensions": {
                  "type": "array",
                  "minItems": 1,
                  "maxItems": 50,
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9]{1,16}$"
                  },
                  "description": "Extensiones sin el punto, sin distinguir mayúsculas, p. ej. `[\"pdf\", \"xml\"]`."
                },
                "filename_pattern": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200,
                  "description": "Expresión regular JavaScript evaluada contra el nombre del archivo, p. ej. `^GUIA_`. Los cuantificadores anidados se rechazan. Un adjunto sin nombre nunca cumple."
                },
                "case_sensitive": {
                  "type": "boolean",
                  "description": "Aplica a `filename_pattern`. Por defecto false."
                }
              }
            }
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          }
        }
      },
      "InboxUpdate": {
        "type": "object",
        "required": [],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
            "description": "Cambiar esto recompone la dirección de recepción a partir de la cadena de slugs — el correo enviado a la dirección anterior deja de llegar. Devuelve 409 en colisión dentro del workspace y 422 cuando la parte local compuesta supera los 64 caracteres."
          },
          "agent_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ]
          },
          "allowed_recipients": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "filters": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "attachments_allow": {
            "type": "boolean"
          },
          "attachments_max_file_number": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "attachments_max_file_size": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "attachments_max_total_size": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "attachments_allow_rules": {
            "type": "array",
            "nullable": true,
            "maxItems": 20,
            "description": "Lista de adjuntos permitidos. Un adjunto se procesa cuando cumple al menos una regla; dentro de una regla, todas las condiciones indicadas deben cumplirse. `null` o `[]` procesa todos los adjuntos. Un adjunto fuera de la lista se ignora, nunca es motivo para rechazar el correo: el agente no lo ve, los límites de adjuntos no lo cuentan y un paso de workflow no puede referenciarlo. En la actualización, omítalo para mantener y envíe `null` para limpiar.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "extensions": {
                  "type": "array",
                  "minItems": 1,
                  "maxItems": 50,
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9]{1,16}$"
                  },
                  "description": "Extensiones sin el punto, sin distinguir mayúsculas, p. ej. `[\"pdf\", \"xml\"]`."
                },
                "filename_pattern": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200,
                  "description": "Expresión regular JavaScript evaluada contra el nombre del archivo, p. ej. `^GUIA_`. Los cuantificadores anidados se rechazan. Un adjunto sin nombre nunca cumple."
                },
                "case_sensitive": {
                  "type": "boolean",
                  "description": "Aplica a `filename_pattern`. Por defecto false."
                }
              }
            }
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          },
          "custom_metadata_mode": {
            "type": "string",
            "enum": [
              "replace",
              "merge"
            ],
            "default": "replace",
            "description": "Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) sobrescribe el objeto completo; `merge` hace deep-merge sobre el valor actual — los objetos anidados se fusionan recursivamente, escalares y arrays sobrescriben la clave, y las claves `null` se conservan (no eliminan la clave). Solo en update."
          }
        }
      },
      "EmailBody": {
        "type": "object",
        "required": [
          "text",
          "html"
        ],
        "properties": {
          "text": {
            "type": "string",
            "nullable": true,
            "description": "Cuerpo del mensaje en texto plano decodificado, o null cuando está ausente o no se puede parsear."
          },
          "html": {
            "type": "string",
            "nullable": true,
            "description": "Cuerpo HTML decodificado. No está sanitizado: los consumidores deben sanitizarlo antes de renderizarlo."
          }
        }
      },
      "Email": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "inbox_id",
          "message_id",
          "from",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid"
          },
          "agent_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "message_id": {
            "type": "string"
          },
          "raw_s3_key": {
            "type": "string"
          },
          "subject": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "format": "email"
          },
          "to": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Destinatarios del envelope (RCPT TO) tal como los entrega SES. Cuando el mensaje fue reenviado automáticamente, este es el address del inbox, no el address que el remitente escribió originalmente."
          },
          "cc": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "bcc": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "header_to": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Valores del header `To:` parseados tal cual. Difiere de `to` cuando el mensaje fue reenviado."
          },
          "forwarded": {
            "type": "boolean",
            "description": "True cuando el destinatario del envelope difiere del header `To:`, o cuando está presente un header de reenvío (Delivered-To, X-Forwarded-To, X-Original-To, Resent-To)."
          },
          "forwarded_for": {
            "type": "string",
            "format": "email",
            "nullable": true,
            "description": "Primer address del header `To:` que no está en el envelope, es decir, el address de cara al cliente que reenvió al inbox."
          },
          "status": {
            "type": "string",
            "enum": [
              "received",
              "approved",
              "rejected",
              "processing",
              "processed",
              "failed"
            ]
          },
          "rejection_reason": {
            "type": "string",
            "nullable": true
          },
          "spam_verdict": {
            "type": "string",
            "nullable": true
          },
          "virus_verdict": {
            "type": "string",
            "nullable": true
          },
          "aws_ses_metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "agent_metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del sistema, escritos por Kobana. Solo lectura."
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Escribibles mediante esta API."
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "processed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "body": {
            "$ref": "#/components/schemas/EmailBody"
          }
        }
      },
      "UsageDay": {
        "type": "object",
        "required": [
          "date",
          "emails",
          "tokens",
          "cost"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "Día UTC."
          },
          "emails": {
            "type": "integer",
            "description": "Correos procesados (ejecuciones de agente exitosas)."
          },
          "tokens": {
            "type": "integer",
            "description": "Tokens de entrada + salida."
          },
          "cost": {
            "type": "number",
            "description": "USD."
          }
        }
      },
      "UsageSummary": {
        "type": "object",
        "description": "Uso del workspace del token en un rango de fechas, agrupado por día UTC.",
        "required": [
          "range",
          "totals",
          "series",
          "monthly"
        ],
        "properties": {
          "range": {
            "type": "object",
            "required": [
              "from",
              "to"
            ],
            "properties": {
              "from": {
                "type": "string",
                "format": "date"
              },
              "to": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "totals": {
            "type": "object",
            "required": [
              "emails",
              "tokens",
              "input_tokens",
              "output_tokens",
              "cost"
            ],
            "properties": {
              "emails": {
                "type": "integer"
              },
              "tokens": {
                "type": "integer"
              },
              "input_tokens": {
                "type": "integer"
              },
              "output_tokens": {
                "type": "integer"
              },
              "cost": {
                "type": "number",
                "description": "USD."
              }
            }
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageDay"
            },
            "description": "Una entrada por día del rango."
          },
          "monthly": {
            "type": "object",
            "description": "Contadores acumulados del mes calendario actual frente a los límites del workspace (se reinician el día 1).",
            "required": [
              "emails_used",
              "emails_limit",
              "cost_used",
              "cost_limit"
            ],
            "properties": {
              "emails_used": {
                "type": "integer"
              },
              "emails_limit": {
                "type": "integer",
                "nullable": true
              },
              "cost_used": {
                "type": "number"
              },
              "cost_limit": {
                "type": "number",
                "nullable": true
              }
            }
          }
        }
      },
      "UsageCost": {
        "type": "object",
        "description": "Costo del workspace del token desglosado por modelo LLM.",
        "required": [
          "range",
          "totals",
          "models",
          "by_model",
          "series"
        ],
        "properties": {
          "range": {
            "type": "object",
            "required": [
              "from",
              "to"
            ],
            "properties": {
              "from": {
                "type": "string",
                "format": "date"
              },
              "to": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "totals": {
            "type": "object",
            "required": [
              "cost",
              "tokens"
            ],
            "properties": {
              "cost": {
                "type": "number",
                "description": "USD."
              },
              "tokens": {
                "type": "integer"
              }
            }
          },
          "models": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids de modelo (`provider/model`) que se ejecutaron en el rango."
          },
          "by_model": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "model",
                "cost",
                "tokens"
              ],
              "properties": {
                "model": {
                  "type": "string"
                },
                "cost": {
                  "type": "number"
                },
                "tokens": {
                  "type": "integer"
                }
              }
            },
            "description": "Totales por modelo, del más caro al más barato."
          },
          "series": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "date",
                "by_model"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "by_model": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "number"
                  },
                  "description": "Costo por id de modelo en ese día (USD)."
                }
              }
            }
          }
        }
      },
      "Model": {
        "type": "object",
        "description": "Un modelo LLM que un agente puede usar: el catálogo del AI Gateway limitado a modelos con precio conocido.",
        "required": [
          "id",
          "provider",
          "model",
          "name",
          "description",
          "pricing"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "anthropic/claude-sonnet-5",
            "description": "Id en el gateway, `provider/model`. El valor aceptado en `Agent.llm_model`."
          },
          "provider": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "pricing": {
            "type": "object",
            "nullable": true,
            "description": "USD por token.",
            "required": [
              "input",
              "output",
              "cache_read",
              "cache_write",
              "valid_from"
            ],
            "properties": {
              "input": {
                "type": "number"
              },
              "output": {
                "type": "number"
              },
              "cache_read": {
                "type": "number"
              },
              "cache_write": {
                "type": "number"
              },
              "valid_from": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "Agent": {
        "type": "object",
        "required": [
          "id",
          "external_id",
          "workspace_id",
          "label",
          "llm_model",
          "system_message"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "nullable": true
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "label": {
            "type": "string"
          },
          "llm_model": {
            "type": "string"
          },
          "system_message": {
            "type": "string"
          },
          "skills_repo": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "version": {
            "type": "integer",
            "description": "Versión actual del prompt. Se incrementa cada vez que cambia `system_message`; cada versión es un snapshot inmutable listado en `/agents/{id}/versions`."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del sistema, escritos por Kobana. Solo lectura."
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Escribibles mediante esta API."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AgentVersion": {
        "type": "object",
        "required": [
          "id",
          "agent_id",
          "version",
          "system_message",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "agent_id": {
            "type": "string",
            "format": "uuid"
          },
          "version": {
            "type": "integer"
          },
          "system_message": {
            "type": "string",
            "description": "Snapshot del prompt de esta versión."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AgentCreate": {
        "type": "object",
        "required": [
          "label",
          "llm_model",
          "system_message"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "description": "Opcional. Por defecto usa el `id` interno generado."
          },
          "label": {
            "type": "string",
            "minLength": 1
          },
          "llm_model": {
            "type": "string",
            "minLength": 1
          },
          "system_message": {
            "type": "string",
            "minLength": 1
          },
          "skills_repo": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          }
        }
      },
      "AgentUpdate": {
        "type": "object",
        "required": [],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1
          },
          "llm_model": {
            "type": "string",
            "minLength": 1
          },
          "system_message": {
            "type": "string"
          },
          "skills_repo": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          },
          "custom_metadata_mode": {
            "type": "string",
            "enum": [
              "replace",
              "merge"
            ],
            "default": "replace",
            "description": "Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) sobrescribe el objeto completo; `merge` hace deep-merge sobre el valor actual — los objetos anidados se fusionan recursivamente, escalares y arrays sobrescriben la clave, y las claves `null` se conservan (no eliminan la clave). Solo en update."
          }
        }
      },
      "AgentRun": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "inbox_id",
          "agent_id",
          "email_id",
          "llm_model",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid"
          },
          "agent_id": {
            "type": "string",
            "format": "uuid"
          },
          "email_id": {
            "type": "string",
            "format": "uuid"
          },
          "agent_version_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Snapshot del prompt con el que se ejecutó la corrida (ver `/agents/{id}/versions`). Nulo para ejecuciones registradas antes de que existiera el versionado."
          },
          "agent_version": {
            "type": "integer",
            "nullable": true,
            "description": "Número de versión del prompt del agente en el momento de la ejecución."
          },
          "llm_model": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "success",
              "failed"
            ]
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "input_tokens": {
            "type": "integer"
          },
          "output_tokens": {
            "type": "integer"
          },
          "cache_read": {
            "type": "integer"
          },
          "cache_write": {
            "type": "integer"
          },
          "cost_per_token": {
            "type": "number"
          },
          "total_cost": {
            "type": "number"
          },
          "duration_ms": {
            "type": "integer",
            "nullable": true
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Webhook": {
        "type": "object",
        "description": "Registro de webhook. Los secretos nunca aparecen en las respuestas: los signing secrets y los cifrados `auth_basic_password`, `auth_bearer_token` y `auth_header_value`. El `signing_secret` en texto claro se devuelve junto a `data` exactamente una vez, al crear y al rotar.",
        "required": [
          "id",
          "external_id",
          "workspace_id",
          "label",
          "url",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "nullable": true
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ]
          },
          "label": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "auth": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "bearer",
              "header"
            ]
          },
          "auth_basic_user": {
            "type": "string",
            "nullable": true,
            "description": "Solo cuando `auth=basic`."
          },
          "auth_header_key": {
            "type": "string",
            "nullable": true,
            "description": "Solo cuando `auth=header`."
          },
          "subscribed_events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "consecutive_failures": {
            "type": "integer"
          },
          "signing_secret_rotated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Cuándo se rotó por última vez el signing secret; `null` si nunca."
          },
          "signing_secret_previous_expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Hasta cuándo el signing secret anterior sigue firmando entregas tras una rotación; `null` cuando no hay ventana de gracia abierta."
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del sistema, escritos por Kobana. Solo lectura."
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Escribibles mediante esta API."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "label",
          "url"
        ],
        "properties": {
          "external_id": {
            "type": "string",
            "minLength": 1,
            "description": "Opcional. Por defecto usa el `id` interno generado."
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "subscribed_events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "auth": {
            "type": "string",
            "enum": [
              "none",
              "basic",
              "bearer",
              "header"
            ],
            "default": "none"
          },
          "auth_basic_user": {
            "type": "string"
          },
          "auth_basic_password": {
            "type": "string"
          },
          "auth_bearer_token": {
            "type": "string"
          },
          "auth_header_key": {
            "type": "string"
          },
          "auth_header_value": {
            "type": "string"
          },
          "signing_secret": {
            "type": "string",
            "pattern": "^whsec_[A-Za-z0-9+/]+={0,2}$",
            "description": "Opcional. Trae tu propio signing secret: `whsec_` + base64 estándar de 24-64 bytes aleatorios. Se genera (32 bytes) si se omite. Se devuelve en texto claro solo en esta respuesta."
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          }
        }
      },
      "WebhookUpdate": {
        "type": "object",
        "required": [],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "subscribed_events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ]
          },
          "custom_metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Metadatos del usuario, formato libre. Envía `null` para limpiarlos. Máx. 64 KB serializados, 16 niveles de profundidad."
          },
          "custom_metadata_mode": {
            "type": "string",
            "enum": [
              "replace",
              "merge"
            ],
            "default": "replace",
            "description": "Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) sobrescribe el objeto completo; `merge` hace deep-merge sobre el valor actual — los objetos anidados se fusionan recursivamente, escalares y arrays sobrescriben la clave, y las claves `null` se conservan (no eliminan la clave). Solo en update."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "required": [
          "id",
          "webhook_id",
          "system_event_id",
          "attempt",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "webhook_id": {
            "type": "string",
            "format": "uuid"
          },
          "system_event_id": {
            "type": "string",
            "format": "uuid"
          },
          "attempt": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "failed"
            ]
          },
          "request_headers": {
            "type": "object",
            "additionalProperties": true
          },
          "request_body": {
            "type": "object",
            "additionalProperties": true
          },
          "response_status": {
            "type": "integer",
            "nullable": true
          },
          "response_headers": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "response_body": {
            "type": "string",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "duration_ms": {
            "type": "integer",
            "nullable": true
          },
          "delivered_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "next_retry_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SystemEvent": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "slug",
          "payload",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "email_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "slug": {
            "type": "string"
          },
          "payload": {
            "type": "object",
            "additionalProperties": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WorkspaceUpsert": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WorkspaceCreate"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid",
                "description": "Coincide por el id interno. Se comprueba antes que `external_id`."
              },
              "external_id": {
                "type": "string",
                "minLength": 1,
                "description": "Coincide por el id del sistema de origen. También se guarda en el registro cuando se crea."
              }
            }
          }
        ],
        "description": "Cuerpo del PUT /workspaces: el cuerpo del POST más las claves de búsqueda `id` / `external_id`."
      },
      "InboxUpsert": {
        "allOf": [
          {
            "$ref": "#/components/schemas/InboxCreate"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid",
                "description": "Coincide por el id interno. Se comprueba antes que `external_id`."
              },
              "external_id": {
                "type": "string",
                "minLength": 1,
                "description": "Coincide por el id del sistema de origen. También se guarda en el registro cuando se crea."
              }
            }
          }
        ],
        "description": "Cuerpo del PUT /inboxes: el cuerpo del POST más las claves de búsqueda `id` / `external_id`."
      },
      "AgentUpsert": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AgentCreate"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid",
                "description": "Coincide por el id interno. Se comprueba antes que `external_id`."
              },
              "external_id": {
                "type": "string",
                "minLength": 1,
                "description": "Coincide por el id del sistema de origen. También se guarda en el registro cuando se crea."
              }
            }
          }
        ],
        "description": "Cuerpo del PUT /agents: el cuerpo del POST más las claves de búsqueda `id` / `external_id`."
      },
      "WebhookUpsert": {
        "allOf": [
          {
            "$ref": "#/components/schemas/WebhookCreate"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid",
                "description": "Coincide por el id interno. Se comprueba antes que `external_id`."
              },
              "external_id": {
                "type": "string",
                "minLength": 1,
                "description": "Coincide por el id del sistema de origen. También se guarda en el registro cuando se crea."
              }
            }
          }
        ],
        "description": "Cuerpo del PUT /webhooks: el cuerpo del POST más las claves de búsqueda `id` / `external_id`."
      },
      "Secret": {
        "type": "object",
        "description": "Un secret del workspace. El valor es de solo escritura: ningún endpoint, en ninguna superficie, lo devuelve.",
        "required": [
          "id",
          "workspace_id",
          "key"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "key": {
            "type": "string",
            "description": "Identificador que un paso de workflow escribe dentro de `${{secrets.KEY}}`. Mayúsculas, dígitos y guiones bajos, empezando por letra.",
            "example": "FINANCE_TOKEN"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Última vez que un paso de workflow interpoló realmente este secret."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SecretCreate": {
        "type": "object",
        "required": [
          "key",
          "value"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[A-Z][A-Z0-9_]{0,62}$",
            "example": "FINANCE_TOKEN"
          },
          "value": {
            "type": "string",
            "maxLength": 65536,
            "description": "Se guarda cifrado; nunca se devuelve."
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SecretUpsert": {
        "type": "object",
        "required": [
          "key",
          "value"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[A-Z][A-Z0-9_]{0,62}$",
            "description": "Clave de búsqueda del upsert."
          },
          "value": {
            "type": "string",
            "maxLength": 65536
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SecretUpdate": {
        "type": "object",
        "required": [],
        "properties": {
          "value": {
            "type": "string",
            "maxLength": 65536,
            "description": "Reemplaza el valor guardado."
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "WorkflowRun": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "status",
          "definition",
          "summary"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "inbox_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "email_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "agent_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "agent_run_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "success",
              "failed"
            ]
          },
          "definition": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "El array `workflow` exactamente como lo devolvió el agente, con los placeholders SIN resolver."
          },
          "summary": {
            "type": "object",
            "required": [
              "total",
              "succeeded",
              "error"
            ],
            "properties": {
              "total": {
                "type": "integer"
              },
              "succeeded": {
                "type": "integer"
              },
              "error": {
                "type": "integer",
                "description": "Pasos que no tuvieron éxito (`total - succeeded`): los `failed` más los `skipped` por referenciar un paso que no tuvo éxito. Una ejecución puede tener varios de cada uno."
              }
            }
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Se completa cuando la ejecución falló: todos los pasos que fallaron, uno por línea, cada uno como `step <posición>: <error>`."
          },
          "duration_ms": {
            "type": "integer",
            "nullable": true
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStep"
            },
            "description": "Solo en `GET /v1/workflow-runs/{id}` — el listado los omite."
          }
        }
      },
      "WorkflowStep": {
        "type": "object",
        "required": [
          "id",
          "workflow_run_id",
          "position",
          "type",
          "status",
          "request",
          "response"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workflow_run_id": {
            "type": "string",
            "format": "uuid"
          },
          "position": {
            "type": "integer",
            "description": "Índice base 0 en el workflow, que también es el orden de ejecución."
          },
          "type": {
            "type": "string",
            "enum": [
              "request"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "success",
              "failed",
              "skipped"
            ]
          },
          "request": {
            "type": "object",
            "required": [
              "method",
              "url",
              "headers",
              "body",
              "form"
            ],
            "properties": {
              "method": {
                "type": "string",
                "nullable": true
              },
              "url": {
                "type": "string",
                "nullable": true,
                "description": "URL tal como se envió, con los valores de secrets reemplazados por `[REDACTED]`."
              },
              "headers": {
                "type": "object",
                "nullable": true,
                "additionalProperties": {
                  "type": "string"
                }
              },
              "body": {
                "type": "string",
                "nullable": true,
                "description": "Truncado a 4000 caracteres. Un adjunto del correo referenciado se muestra como `[attachment N: nombre, content type, tamaño]`, no como sus bytes."
              },
              "form": {
                "type": "object",
                "nullable": true,
                "description": "Campos multipart de un paso con `form`, tal como se enviaron. Un campo de archivo es un descriptor `{ attachment, filename, content_type, size }` del adjunto del correo que se subió.",
                "additionalProperties": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "object",
                      "required": [
                        "attachment",
                        "filename",
                        "content_type",
                        "size"
                      ],
                      "properties": {
                        "attachment": {
                          "type": "integer",
                          "description": "Índice base 0 en el correo."
                        },
                        "filename": {
                          "type": "string"
                        },
                        "content_type": {
                          "type": "string"
                        },
                        "size": {
                          "type": "integer",
                          "description": "Bytes."
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "response": {
            "type": "object",
            "required": [
              "status",
              "headers",
              "body",
              "expected_status"
            ],
            "properties": {
              "status": {
                "type": "integer",
                "nullable": true
              },
              "headers": {
                "type": "object",
                "nullable": true,
                "additionalProperties": {
                  "type": "string"
                }
              },
              "body": {
                "type": "string",
                "nullable": true,
                "description": "Truncado a 4000 caracteres."
              },
              "expected_status": {
                "type": "integer",
                "nullable": true,
                "description": "Status que cuenta como éxito. Null significa cualquier 2xx."
              }
            }
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "duration_ms": {
            "type": "integer",
            "nullable": true
          },
          "started_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finished_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Me": {
        "type": "object",
        "description": "Identidad detrás del token Bearer. Nunca incluye el token ni nada que lo identifique.",
        "required": [
          "user",
          "organization",
          "token"
        ],
        "properties": {
          "user": {
            "type": "object",
            "nullable": true,
            "description": "La persona detrás del token. `null` cuando el token no es de una persona.",
            "required": [
              "id",
              "name",
              "email"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string",
                "nullable": true
              },
              "email": {
                "type": "string",
                "format": "email"
              }
            }
          },
          "organization": {
            "type": "object",
            "required": [
              "id",
              "name",
              "external_id"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "external_id": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "token": {
            "type": "object",
            "required": [
              "type",
              "scopes",
              "access_level",
              "expires_at"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "oauth",
                  "api_key"
                ],
                "description": "`oauth` para un token emitido por un flujo de autorización; `api_key` para uno creado manualmente en el servidor de autorización."
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "access_level": {
                "type": "string",
                "enum": [
                  "read",
                  "write",
                  "all"
                ]
              },
              "expires_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT RS256 emitido por el Authorization Server de Kobana (`iss` = `https://account[.<env>].kobana.com.br`), verificado contra las claves públicas que publica — esta API no guarda clave de firma y no puede emitir tokens. Claims: `iss`, `aud=https://api.inbox[.<env>].kobana.com.br` (puede ser una lista; la regla es *contiene*), `sub`, `jti`, `exp` (obligatoria), `scope` (lista separada por espacios) y `src` opcional (`user`|`system`). Los scopes tienen dos ejes: un recurso, siempre con el prefijo de la app (`inbox/emails`), y un verbo global (`write`). Un recurso sin verbo lee; una escritura necesita ambos (`inbox/emails write`). `inbox/all` es el comodín de recurso — lee todos los recursos y no concede verbo. La forma granular `inbox/emails:write` satisface ambos ejes para ese recurso por sí sola."
      }
    }
  }
}
