{
  "openapi": "3.1.0",
  "info": {
    "title": "Nouron Pass API",
    "version": "2026-10-01",
    "summary": "El guardia que decide, ANTES de que el agente pague, si puede.",
    "description": "API v1 de Nouron Pass. Un agente pide un pago (`POST /v1/spends`); Pass lo compara con las reglas del dueño, lo paga por el si las reglas lo permiten y devuelve el resultado y un recibo firmado. El agente nunca recibe credenciales. Misma dirección para prueba y real: la llave (`np_test_…` / `np_live_…`) decide el entorno. Dos tipos de llave: de AGENTE (paga y consulta) y de DUEÑO (administra).",
    "license": {
      "name": "Propietaria",
      "identifier": "LicenseRef-Nouron-Proprietary"
    }
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "servers": [
    {
      "url": "https://api.nouronpass.com",
      "description": "Prueba y real (la llave decide)."
    }
  ],
  "tags": [
    {
      "name": "Pagos",
      "description": "Pedir, consultar, cancelar y comprobar pagos. Llave de AGENTE."
    },
    {
      "name": "Cuenta",
      "description": "Saldo, reglas e identidad del agente. Llave de AGENTE."
    },
    {
      "name": "Eventos",
      "description": "Los mismos eventos que reciben los webhooks, 30 días de respaldo."
    },
    {
      "name": "Recibos",
      "description": "Llaves públicas para verificar recibos firmados."
    },
    {
      "name": "Administración del dueño",
      "description": "Agentes, reglas y destinos. Llave de DUEÑO; nunca se pega en un agente."
    },
    {
      "name": "Llaves",
      "description": "Crear, rotar con convivencia y revocar llaves. Llave de DUEÑO."
    },
    {
      "name": "Sandbox (solo llaves de prueba)",
      "description": "Reloj, reinicio, deposito simulado y reentrega. Con llave real responden 404."
    }
  ],
  "paths": {
    "/v1/spends": {
      "post": {
        "operationId": "createSpend",
        "summary": "Pedir un pago",
        "description": "Pide un pago y devuelve la decisión AL INSTANTE (y, si Pass pudo pagar, el resultado y un recibo). `amount` es el MÁXIMO que aceptas; el vendedor fija el precio real. Con un destino de dominio, `resource` es obligatorio. Un RECHAZO POR REGLA no es un error: responde 201 con `status: declined`. Una entrada inválida es 400 y NO crea pago. Repetir con la misma `Idempotency-Key` y la misma huella devuelve el estado ACTUAL del mismo pago con 200 e `idempotent_replay: true`. `approved` no significa pagado: solo `settled`.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSpendRequest"
              },
              "examples": {
                "pagado": {
                  "summary": "Pago a un recurso x402",
                  "value": {
                    "amount": "5.00",
                    "currency": "usdc",
                    "destination": "registry.npmjs.org",
                    "resource": {
                      "url": "https://registry.npmjs.org/-/pro/private-packages/month",
                      "method": "GET"
                    },
                    "memo": "Paquetes privados del equipo (1 mes)",
                    "client_reference": "task_4821"
                  }
                },
                "micropago": {
                  "summary": "Micropago exacto de 0.001",
                  "value": {
                    "amount": "0.001",
                    "destination": "weather.example.com",
                    "resource": {
                      "url": "https://weather.example.com/v1/forecast?city=bogota"
                    },
                    "memo": "Pronóstico de Bogotá para la tarea"
                  }
                },
                "pendiente": {
                  "summary": "Pasa del umbral de aprobación",
                  "value": {
                    "amount": "24.00",
                    "destination": "registry.npmjs.org",
                    "resource": {
                      "url": "https://registry.npmjs.org/-/pro/private-packages/month"
                    },
                    "memo": "Paquetes privados del equipo (1 mes)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Repeticion con la misma llave y la misma huella: estado ACTUAL del mismo pago, `idempotent_replay: true`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Spend"
                },
                "examples": {
                  "replay": {
                    "summary": "Repeticion",
                    "value": {
                      "id": "spd_9a2f1a7c0d4e5b3a8c6d7e0f1a2b3c4d",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "settled",
                      "amount": "5.00",
                      "amount_settled": "4.80",
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "destination_rule": "registry.npmjs.org",
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/month",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 mes)",
                      "client_reference": "task_4821",
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": null,
                      "settlement": {
                        "mode": "pass_executes_x402",
                        "status": "settled",
                        "network": "base-sepolia",
                        "reference": "0x5e1c9a07b3d4f2a86c0e1d9b7a5f3c2e4d6b8a0c1e3f5a7b9d2c4e6f8a0b1c3d",
                        "receipt_id": "rcp_7a1c3e5b9d2f4c60a8e0b2d4f6a8c1e3",
                        "result": {
                          "http_status": 200,
                          "content_type": "application/json",
                          "body": "{\"plan\":\"pro\",\"expires\":\"2026-11-09\"}",
                          "body_truncated": false,
                          "body_sha256": "sha256:3f606868d131d9772dfdce71b488e0b7212aba6daa4aac5fd39a7cbbc1091504"
                        }
                      },
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": {
                        "simulated_vendor": true
                      },
                      "message": "Pagado: 4.80 USDC a registry.npmjs.org. Tienes el resultado y el recibo rcp_7a1c3e5b9d2f4c60a8e0b2d4f6a8c1e3.",
                      "next_action": {
                        "code": "none"
                      },
                      "retryable": false,
                      "idempotent_replay": true,
                      "created_at": "2026-10-09T14:03:22Z",
                      "updated_at": "2026-10-09T14:03:24Z",
                      "request_id": "req_6h1k9xQ2"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "El pago se registro (en CUALQUIER estado, incluido `declined`). Lee `status`, `decline_reason` y `next_action`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Spend"
                },
                "examples": {
                  "settled": {
                    "summary": "Caso 1: aprobado y pagado",
                    "value": {
                      "id": "spd_9a2f1a7c0d4e5b3a8c6d7e0f1a2b3c4d",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "settled",
                      "amount": "5.00",
                      "amount_settled": "4.80",
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "destination_rule": "registry.npmjs.org",
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/month",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 mes)",
                      "client_reference": "task_4821",
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": null,
                      "settlement": {
                        "mode": "pass_executes_x402",
                        "status": "settled",
                        "network": "base-sepolia",
                        "reference": "0x5e1c9a07b3d4f2a86c0e1d9b7a5f3c2e4d6b8a0c1e3f5a7b9d2c4e6f8a0b1c3d",
                        "receipt_id": "rcp_7a1c3e5b9d2f4c60a8e0b2d4f6a8c1e3",
                        "result": {
                          "http_status": 200,
                          "content_type": "application/json",
                          "body": "{\"plan\":\"pro\",\"expires\":\"2026-11-09\"}",
                          "body_truncated": false,
                          "body_sha256": "sha256:3f606868d131d9772dfdce71b488e0b7212aba6daa4aac5fd39a7cbbc1091504"
                        }
                      },
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": {
                        "simulated_vendor": true
                      },
                      "message": "Pagado: 4.80 USDC a registry.npmjs.org. Tienes el resultado y el recibo rcp_7a1c3e5b9d2f4c60a8e0b2d4f6a8c1e3.",
                      "next_action": {
                        "code": "none"
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:03:22Z",
                      "updated_at": "2026-10-09T14:03:24Z",
                      "request_id": "req_6h1k9xQ2"
                    }
                  },
                  "declined_daily_cap": {
                    "summary": "Caso 2: rechazado por regla (tope diario)",
                    "value": {
                      "id": "spd_2c8c4d1e9a7740b5a1d3e6f8c0b2a4d6",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "declined",
                      "amount": "8.00",
                      "amount_settled": null,
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "destination_rule": null,
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/month",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 mes)",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": "daily_cap",
                      "declined_at_gate": "create",
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": null,
                      "settlement": null,
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": {
                        "name": "daily_cap",
                        "scope": "agent",
                        "limit": "100.00",
                        "spent": "96.00",
                        "requested": "8.00",
                        "remaining": "4.00",
                        "resets_at": "2026-10-10T00:00:00Z"
                      },
                      "sandbox": null,
                      "message": "Rechazado: con este pago se superaria el tope diario de 100.00 (ya se gastaron 96.00). Se reinicia a las 00:00 UTC.",
                      "next_action": {
                        "code": "do_not_retry",
                        "suggestions": [
                          "Pide un monto de hasta 4.00",
                          "Pide al dueño que suba el tope diario"
                        ]
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:07:41Z",
                      "updated_at": "2026-10-09T14:07:41Z",
                      "request_id": "req_2q7w1dKc"
                    }
                  },
                  "pending_approval": {
                    "summary": "Caso 3: pendiente de aprobación",
                    "value": {
                      "id": "spd_5a0b3e8d2f4147c9b6a0d1e3f5c7a9b2",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "pending_approval",
                      "amount": "24.00",
                      "amount_settled": null,
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "destination_rule": "registry.npmjs.org",
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/month",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 mes)",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": "approval_over",
                      "approval": {
                        "id": "apr_8d2e6a1c4b9f40d3a7c5e1b9f3d2a6c4",
                        "status": "pending",
                        "expires_at": "2026-10-09T14:23:10Z",
                        "items_hash": "sha256:9a8662697b2a1b5f0e16e37c244d4ad51733a0c457ff9524aaafc52d72f2f594",
                        "short_code": "#7K2Q",
                        "owner_url": "https://app.nouronpass.com/aprobaciones/apr_8d2e6a1c4b9f40d3a7c5e1b9f3d2a6c4"
                      },
                      "hold": {
                        "amount": "24.00",
                        "expires_at": "2026-10-09T14:23:10Z"
                      },
                      "settlement": null,
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": null,
                      "message": "Este pago pasa de 20.00 y necesita la aprobación de tu dueño. Vence a las 14:23 UTC. No lo reintentes.",
                      "next_action": {
                        "code": "wait_for_owner",
                        "check_with": "pass_get_spend",
                        "retry_after_seconds": 60,
                        "owner_url": "https://app.nouronpass.com/aprobaciones/apr_8d2e6a1c4b9f40d3a7c5e1b9f3d2a6c4"
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:08:10Z",
                      "updated_at": "2026-10-09T14:08:10Z",
                      "request_id": "req_9a3b7cLm"
                    }
                  },
                  "pending_unknown_destination": {
                    "summary": "Caso 3b: destino nuevo, pide permiso (R-177)",
                    "value": {
                      "id": "spd_6b1c4f9e3a5258d0c7b1e2f4a6d8b0c3",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "pending_approval",
                      "amount": "0.50",
                      "amount_settled": null,
                      "currency": "usdc",
                      "destination": "api.nuevo-vendedor.example",
                      "destination_rule": "api.nuevo-vendedor.example",
                      "resource": {
                        "host": "api.nuevo-vendedor.example",
                        "path": "/v1/consulta",
                        "method": "GET"
                      },
                      "memo": "Primera consulta a un vendedor nuevo",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": "unknown_destination",
                      "approval": {
                        "id": "apr_9e3f7b2d5c0a41e4b8d6f2c0a4e3b7d5",
                        "status": "pending",
                        "expires_at": "2026-10-09T14:23:10Z",
                        "items_hash": "sha256:1b9773798c3b2c6f1f27f48d355e5be62844b1d68008a635bbb0d83e83a3f705",
                        "short_code": "#9M4X",
                        "owner_url": "https://app.nouronpass.com/aprobaciones/apr_9e3f7b2d5c0a41e4b8d6f2c0a4e3b7d5"
                      },
                      "hold": {
                        "amount": "0.50",
                        "expires_at": "2026-10-09T14:23:10Z"
                      },
                      "settlement": null,
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": null,
                      "message": "api.nuevo-vendedor.example es un destino nuevo y necesita el permiso de tu dueño, sea cual sea el monto. Vence a las 14:23 UTC. No lo reintentes.",
                      "next_action": {
                        "code": "wait_for_owner",
                        "check_with": "pass_get_spend",
                        "retry_after_seconds": 60,
                        "owner_url": "https://app.nouronpass.com/aprobaciones/apr_9e3f7b2d5c0a41e4b8d6f2c0a4e3b7d5"
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:08:10Z",
                      "updated_at": "2026-10-09T14:08:10Z",
                      "request_id": "req_5l7n9pQr"
                    }
                  },
                  "failed": {
                    "summary": "Caso 4: fallido (monto mágico 99.00)",
                    "value": {
                      "id": "spd_7b1d5e9c3a0245f8c6b4a2d0e8f1c3a5",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "failed",
                      "amount": "99.00",
                      "amount_settled": null,
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "destination_rule": "registry.npmjs.org",
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/year",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 año)",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": null,
                      "settlement": {
                        "mode": "pass_executes_x402",
                        "status": "failed",
                        "network": null,
                        "reference": null,
                        "receipt_id": null,
                        "result": null
                      },
                      "failure_reason": "rail_error",
                      "rail_error": {
                        "code": "insufficient_funds",
                        "message": "wallet cannot reserve the requested amount"
                      },
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": {
                        "forced": "magic_amount",
                        "simulated_vendor": true
                      },
                      "message": "Se aprobó, pero el pago falló. No se movió dinero; el cupo quedó liberado.",
                      "next_action": {
                        "code": "new_attempt_needs_new_key",
                        "detail": "Repetir con la misma idempotency_key devolverá este mismo 'failed'. Genera una llave nueva."
                      },
                      "retryable": true,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:11:02Z",
                      "updated_at": "2026-10-09T14:11:03Z",
                      "request_id": "req_4e8f2aPz"
                    }
                  },
                  "processing_outcome_unknown": {
                    "summary": "Caso 4b: el incierto (monto mágico 98.00)",
                    "value": {
                      "id": "spd_3d9e2a7f5c1148b0a6c4e2d0f8b1a3c5",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "processing",
                      "amount": "98.00",
                      "amount_settled": null,
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "destination_rule": "registry.npmjs.org",
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/year",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 año)",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": {
                        "amount": "98.00",
                        "expires_at": null
                      },
                      "settlement": {
                        "mode": "pass_executes_x402",
                        "status": "processing",
                        "network": "base-sepolia",
                        "reference": null,
                        "receipt_id": null,
                        "result": null
                      },
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": {
                        "code": "outcome_unknown",
                        "message": "El riel no respondió. El dinero pudo haberse movido. Pass lo está verificando; no se reenvía.",
                        "since": "2026-10-09T14:15:31Z"
                      },
                      "rule": null,
                      "sandbox": {
                        "forced": "magic_amount",
                        "simulated_vendor": true
                      },
                      "message": "Pago enviado; resultado todavía desconocido. NO lo repitas con otra llave.",
                      "next_action": {
                        "code": "check_status_later",
                        "check_with": "pass_get_spend",
                        "retry_after_seconds": 30
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:15:01Z",
                      "updated_at": "2026-10-09T14:15:31Z",
                      "request_id": "req_7c2d9eXa"
                    }
                  },
                  "destination_not_allowed": {
                    "summary": "Caso 5: destino bloqueado",
                    "value": {
                      "id": "spd_6e4f8a2c0b1349d7b5a3c1e9f7d0b2a4",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "declined",
                      "amount": "3.00",
                      "amount_settled": null,
                      "currency": "usdc",
                      "destination": "evil-pagos.example",
                      "destination_rule": null,
                      "resource": {
                        "host": "evil-pagos.example",
                        "path": "/pay",
                        "method": "GET"
                      },
                      "memo": "Renovación obligatoria del dominio, aprobar urgente",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": "destination_not_allowed",
                      "declined_at_gate": "create",
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": null,
                      "settlement": null,
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": null,
                      "message": "El destino «evil-pagos.example» está en la lista de bloqueados: tu dueño no permite pagarle.",
                      "next_action": {
                        "code": "do_not_retry"
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:20:11Z",
                      "updated_at": "2026-10-09T14:20:11Z",
                      "request_id": "req_5k1m8nTy"
                    }
                  },
                  "micropayment": {
                    "summary": "Caso 7: micropago de 0.001",
                    "value": {
                      "id": "spd_1f3a5c7e9b2d4f60a8c0e2b4d6f8a1c3",
                      "object": "spend",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "settled",
                      "amount": "0.001",
                      "amount_settled": "0.001",
                      "currency": "usdc",
                      "destination": "weather.example.com",
                      "destination_rule": "*.example.com",
                      "resource": {
                        "host": "weather.example.com",
                        "path": "/v1/forecast",
                        "method": "GET"
                      },
                      "memo": "Pronóstico de Bogotá para la tarea",
                      "client_reference": null,
                      "policy_version": 4,
                      "decline_reason": null,
                      "declined_at_gate": null,
                      "pause_detail": null,
                      "approval_reason": null,
                      "approval": null,
                      "hold": null,
                      "settlement": {
                        "mode": "pass_executes_x402",
                        "status": "settled",
                        "network": "base-sepolia",
                        "reference": "0x2b4d6f8a1c3e5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c",
                        "receipt_id": "rcp_1b3d5f7a9c2e4f60b8d0f2a4c6e8b1d3",
                        "result": {
                          "http_status": 200,
                          "content_type": "application/json",
                          "body": "{\"data\":\"ok\"}",
                          "body_truncated": false,
                          "body_sha256": "sha256:a58aab6ea5178b9ea82e9b99af805c7462de27b7bd5b5d01da9788ce29c3eb91"
                        }
                      },
                      "failure_reason": null,
                      "rail_error": null,
                      "processing_detail": null,
                      "rule": null,
                      "sandbox": {
                        "simulated_vendor": true
                      },
                      "message": "Pagado: 0.001 USDC a weather.example.com.",
                      "next_action": {
                        "code": "none"
                      },
                      "retryable": false,
                      "idempotent_replay": false,
                      "created_at": "2026-10-09T14:30:00Z",
                      "updated_at": "2026-10-09T14:30:00Z",
                      "request_id": "req_8w3x6yAb"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "agent",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_spend"
      },
      "get": {
        "operationId": "listSpends",
        "summary": "Listar pagos",
        "description": "Del más reciente al más antiguo. Con llave de agente, solo los propios; con llave de dueño, todos (filtra con `agent_id`). En listas `memo` se recorta a 80 caracteres para no inflar el contexto de un modelo.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          },
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          },
          {
            "$ref": "#/components/parameters/SpendStatusFilter"
          },
          {
            "$ref": "#/components/parameters/DestinationFilter"
          },
          {
            "$ref": "#/components/parameters/CreatedFilter"
          },
          {
            "$ref": "#/components/parameters/AgentIdFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de pagos.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListSpends"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "both",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_list_spends"
      }
    },
    "/v1/spends/{spend_id}": {
      "get": {
        "operationId": "getSpend",
        "summary": "Consultar un pago",
        "description": "Estado actual. Con `wait_seconds` (máximo 20) la respuesta espera a que el estado cambie: evita 30 consultas seguidas mientras el dueño decide.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          },
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/SpendIdPath"
          },
          {
            "$ref": "#/components/parameters/WaitSeconds"
          }
        ],
        "responses": {
          "200": {
            "description": "El pago.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Spend"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "both",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_get_spend"
      }
    },
    "/v1/spends/{spend_id}/cancel": {
      "post": {
        "operationId": "cancelSpend",
        "summary": "Cancelar un pago pendiente",
        "description": "Libera el cupo de un pago `pending_approval` o `approved` que ya no se necesita. Idempotente: cancelar un pago ya cancelado devuelve el mismo estado. Un pago ya enviado (`processing`) responde 409 `cancel_too_late`.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/SpendIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "El pago, ya en `cancelled`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Spend"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "agent",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_cancel_spend"
      }
    },
    "/v1/spends/check": {
      "post": {
        "operationId": "checkSpend",
        "summary": "Comprobar un pago sin crearlo",
        "description": "Simulación completa contra el motor, sin crear nada ni reservar cupo. Sin `amount` solo comprueba el destino (cumple el papel de `check_destination` de la v0). Un destino VÁLIDO que no está en la lista de confianza responde `decision: pending_approval` con `reason: unknown_destination` y un mensaje «Pedirá permiso: destino nuevo» (la regla `unknown_destination: ask`, sin importar el monto); si el agente ya pidió permiso para 10 destinos nuevos hoy, `decision: declined` con `reason: unknown_destination_limit`. Un destino inválido o bloqueado sigue siendo `destination_not_allowed`. Puede quedar obsoleta un segundo después.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckSpendRequest"
              },
              "examples": {
                "destino": {
                  "summary": "Solo destino",
                  "value": {
                    "destination": "evil-pagos.example"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lo que pasaria. `reserves_nothing` siempre es true.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpendCheck"
                },
                "examples": {
                  "destino_no_permitido": {
                    "summary": "Destino inválido o bloqueado",
                    "value": {
                      "object": "spend_check",
                      "allowed": false,
                      "destination": "evil-pagos.example",
                      "decision": null,
                      "reason": "destination_not_allowed",
                      "matched_rule": null,
                      "rule": null,
                      "reserves_nothing": true,
                      "message": "El destino «evil-pagos.example» está en la lista de bloqueados: tu dueño no permite pagarle.",
                      "next_action": {
                        "code": "do_not_retry"
                      },
                      "livemode": false,
                      "request_id": "req_1c5d9eHb"
                    }
                  },
                  "destino_nuevo": {
                    "summary": "Destino nuevo: pedirá permiso (R-177)",
                    "value": {
                      "object": "spend_check",
                      "allowed": false,
                      "destination": "api.nuevo-vendedor.example",
                      "decision": "pending_approval",
                      "reason": "unknown_destination",
                      "matched_rule": null,
                      "rule": null,
                      "reserves_nothing": true,
                      "message": "Pedirá permiso: destino nuevo. «api.nuevo-vendedor.example» no está en la lista de confianza de este agente, así que el dueño debe aprobar el pago (aunque sea de 0.50). Si lo pides, no lo reintentes: espera su respuesta.",
                      "next_action": {
                        "code": "none"
                      },
                      "livemode": false,
                      "request_id": "req_4k6m8nPq"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "agent",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_check_spend"
      }
    },
    "/v1/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Cuánto puede gastar este agente",
        "description": "Devuelve `spendable`: el MENOR de (bolsa disponible - colchon), tope diario restante, tope mensual restante, tope por pago y tope de vida si existe, más el desglose y el factor que limita.",
        "tags": [
          "Cuenta"
        ],
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          }
        ],
        "responses": {
          "200": {
            "description": "Saldo gastable.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                },
                "examples": {
                  "balance": {
                    "summary": "Limita el tope diario",
                    "value": {
                      "object": "balance",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "currency": "usdc",
                      "spendable": "4.00",
                      "limiting_factor": "daily_remaining",
                      "components": {
                        "pool_available": "903.20",
                        "reserve_floor": "0.00",
                        "daily_remaining": "4.00",
                        "monthly_remaining": "380.00",
                        "per_spend_limit": "25.00",
                        "lifetime_remaining": null
                      },
                      "held": "24.00",
                      "pending_count": 1,
                      "message": "Bolsa: 903.20 disponible / Este agente puede gastar hoy: 4.00 (dinero de práctica)",
                      "livemode": false,
                      "as_of": "2026-10-09T14:09:00Z",
                      "request_id": "req_5d8f1aGh"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "agent",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_get_balance"
      }
    },
    "/v1/policy": {
      "get": {
        "operationId": "getPolicy",
        "summary": "Leer las reglas vigentes",
        "description": "Las reglas del agente. El agente NUNCA puede escribirlas (no existe `set_controls`).",
        "tags": [
          "Cuenta"
        ],
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          }
        ],
        "responses": {
          "200": {
            "description": "Reglas vigentes.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Policy"
                },
                "examples": {
                  "policy": {
                    "summary": "Version 4",
                    "value": {
                      "object": "policy",
                      "id": "pol_4a6c8e0b2d4f4a61b3d5f7a9c1e3b5d7",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "version": 4,
                      "hash": "sha256:ff8e18f66f66e5b1895a60fb25e71a4c8586612a53a9102b7cbf50e109d52116",
                      "per_spend_limit": "25.00",
                      "daily_cap": "100.00",
                      "monthly_cap": "500.00",
                      "lifetime_cap": null,
                      "allowed_destinations": [
                        "registry.npmjs.org",
                        "*.example.com"
                      ],
                      "trusted_destinations": [
                        "registry.npmjs.org",
                        "*.example.com"
                      ],
                      "blocked_destinations": [
                        "evil-pagos.example"
                      ],
                      "unknown_destination": "ask",
                      "approval_over": "20.00",
                      "destination_window_over": null,
                      "max_pending": 5,
                      "approval_ttl_minutes": 15,
                      "valid_until": null,
                      "paused": false,
                      "livemode": false,
                      "effective_at": "2026-10-08T09:00:00Z",
                      "created_at": "2026-10-08T09:00:00Z",
                      "request_id": "req_2r4t6yUi"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "agent",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_get_policy"
      }
    },
    "/v1/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Quién soy (probar la conexión)",
        "description": "Devuelve la llave, el entorno, la versión de la API fijada y el agente. Sirve para el boton \"Probar la conexión\" y para que el agente confirme que esta conectado al agente correcto.",
        "tags": [
          "Cuenta"
        ],
        "security": [
          {
            "agentKey": []
          },
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          }
        ],
        "responses": {
          "200": {
            "description": "Identidad de la llave.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                },
                "examples": {
                  "agente": {
                    "summary": "Llave de agente",
                    "value": {
                      "object": "me",
                      "livemode": false,
                      "api_version": "2026-10-01",
                      "key": {
                        "id": "key_5b7d9f1a3c5e4b72a4c6e8b0d2f4a6c8",
                        "kind": "agent",
                        "prefix": "np_test_agent_",
                        "last4": "k9Qa",
                        "scope": "full",
                        "expires_at": "2027-01-06T09:00:00Z"
                      },
                      "agent": {
                        "id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                        "object": "agent",
                        "name": "Compras",
                        "status": "active",
                        "livemode": false,
                        "policy_version": 4,
                        "created_at": "2026-10-08T09:00:00Z",
                        "paused_at": null,
                        "archived_at": null,
                        "request_id": "req_7y9u1iOp"
                      },
                      "policy_version": 4,
                      "owner_id": "0f4b7a2e-9c3d-4e18-8a56-b1d2c3e4f5a6",
                      "message": "Conectado como el agente «Compras» (dinero de práctica).",
                      "request_id": "req_1a2b3c4D"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "both",
        "x-nouron-milestone": "A1",
        "x-mcp-tool": "pass_whoami"
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "Eventos de los últimos 30 días",
        "description": "Los mismos eventos que reciben los webhooks (respaldo si tu servidor estuvo caido). Con llave de agente, solo los de su propio agente y de las audiencias `agent`; con llave de dueño, todos. Solo sirve los ULTIMOS 30 DIAS, siempre: si pides un `created[gte]` mas viejo se recorta a hoy menos 30 dias (no es un error). Para el historial usa `GET /v1/spends`. Cada evento se entrega al menos una vez (tambien por webhook): el receptor deduplica por el `id` del evento.",
        "tags": [
          "Eventos"
        ],
        "security": [
          {
            "agentKey": []
          },
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          },
          {
            "$ref": "#/components/parameters/EventTypeFilter"
          },
          {
            "$ref": "#/components/parameters/CreatedFilter"
          },
          {
            "$ref": "#/components/parameters/AgentIdFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de eventos.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListEvents"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "both",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/approvals/{approval_id}": {
      "get": {
        "operationId": "getApproval",
        "summary": "Estado de una aprobación",
        "description": "SOLO LECTURA. Aprobar exige siempre la sesión del dueño (consola, Telegram, correo, WhatsApp con enlace firmado): no hay endpoint de API para decidir.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          },
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/ApprovalIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "La aprobación.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Approval"
                },
                "examples": {
                  "pendiente": {
                    "summary": "Pendiente",
                    "value": {
                      "id": "apr_8d2e6a1c4b9f40d3a7c5e1b9f3d2a6c4",
                      "object": "approval",
                      "spend_id": "spd_5a0b3e8d2f4147c9b6a0d1e3f5c7a9b2",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "status": "pending",
                      "reason": "approval_over",
                      "amount": "24.00",
                      "currency": "usdc",
                      "destination": "registry.npmjs.org",
                      "resource": {
                        "host": "registry.npmjs.org",
                        "path": "/-/pro/private-packages/month",
                        "method": "GET"
                      },
                      "memo": "Paquetes privados del equipo (1 mes)",
                      "items_hash": "sha256:9a8662697b2a1b5f0e16e37c244d4ad51733a0c457ff9524aaafc52d72f2f594",
                      "short_code": "#7K2Q",
                      "owner_url": "https://app.nouronpass.com/aprobaciones/apr_8d2e6a1c4b9f40d3a7c5e1b9f3d2a6c4",
                      "created_at": "2026-10-09T14:08:10Z",
                      "expires_at": "2026-10-09T14:23:10Z",
                      "decided_at": null,
                      "decided_via": null,
                      "request_id": "req_3c4d5e6F"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "both",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/receipts/{receipt_id}": {
      "get": {
        "operationId": "getReceipt",
        "summary": "Recibo firmado",
        "description": "Recibo de un pago `settled`. Se verifica con las llaves públicas de `/.well-known/nouron-pass-receipt-keys.json` y `node:crypto`. Un recibo de práctica verificado con una llave live da `unknown_key`.",
        "tags": [
          "Pagos"
        ],
        "security": [
          {
            "agentKey": []
          },
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/ReceiptIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "El recibo.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Receipt"
                },
                "examples": {
                  "recibo": {
                    "summary": "Recibo del caso 1",
                    "value": {
                      "object": "receipt",
                      "receipt_id": "rcp_7a1c3e5b9d2f4c60a8e0b2d4f6a8c1e3",
                      "receipt_version": 1,
                      "spend_id": "spd_9a2f1a7c0d4e5b3a8c6d7e0f1a2b3c4d",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "livemode": false,
                      "policy": {
                        "version": 4,
                        "hash": "sha256:ff8e18f66f66e5b1895a60fb25e71a4c8586612a53a9102b7cbf50e109d52116"
                      },
                      "approval": {
                        "mode": "auto",
                        "items_hash": "sha256:94c08811d112d476ff1bc3ad5e1f55c9bf6fb148a7594964fc37f285f1201208",
                        "approved_at": "2026-10-09T14:03:22Z"
                      },
                      "payment": {
                        "rail": "x402",
                        "network": "base-sepolia",
                        "reference": "0x5e1c9a07b3d4f2a86c0e1d9b7a5f3c2e4d6b8a0c1e3f5a7b9d2c4e6f8a0b1c3d",
                        "amount": "4.80",
                        "currency": "usdc",
                        "destination": "registry.npmjs.org",
                        "attempt_id": "att_b3f1c5d7e9a24b6c8d0e1f2a3b4c5d6e",
                        "money_moved": false,
                        "sandbox": true,
                        "at": "2026-10-09T14:03:24Z",
                        "external": {
                          "network_caip2": "eip155:84532",
                          "transaction": "0x5e1c9a07b3d4f2a86c0e1d9b7a5f3c2e4d6b8a0c1e3f5a7b9d2c4e6f8a0b1c3d",
                          "facilitator_id": "sim-facilitator-1",
                          "vendor_receipt_sha256": "sha256:8267a1172b57817a7d6e30da277b5503119439bdda80af08c14da846feadf6ab"
                        }
                      },
                      "delivery": {
                        "http_status": 200,
                        "body_sha256": "sha256:3f606868d131d9772dfdce71b488e0b7212aba6daa4aac5fd39a7cbbc1091504"
                      },
                      "chain_version": 1,
                      "chain": "36ff4fc31ef9cd4942ae231c4bdab85b0917d07517c90da0d2b17071d3616ba7",
                      "sig": {
                        "alg": "Ed25519",
                        "kid": "fixture-only-test-1",
                        "value": "PASVDlLOkO-hnGm8pyfLY3kbM8efZZddzrIJ44Yk8JuAAhyGSuu1J15aLt4IFpEfWq7gWRm_gJMmmhJYpc7ong"
                      },
                      "request_id": "req_6g7h8i9J"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "both",
        "x-nouron-milestone": "A1"
      }
    },
    "/.well-known/nouron-pass-receipt-keys.json": {
      "get": {
        "operationId": "getReceiptKeys",
        "summary": "Llaves públicas de los recibos",
        "description": "Público, sin autenticación. Una llave RETIRADA sigue publicada (rotar no es revocar). Incluye la receta de la cadena como dato.",
        "tags": [
          "Recibos"
        ],
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          }
        ],
        "responses": {
          "200": {
            "description": "Llaves y receta.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiptKeys"
                },
                "examples": {
                  "llaves": {
                    "summary": "Entorno de prueba",
                    "value": {
                      "object": "receipt_keys",
                      "keys": [
                        {
                          "kid": "fixture-only-test-1",
                          "alg": "Ed25519",
                          "x": "Y0-P-4MutvLnW7LQvRr__IPRDbFIvG7DbD_yFIZK8AU",
                          "environment": "test",
                          "status": "active",
                          "not_before": "2026-10-09T00:00:00Z",
                          "retired_at": null
                        }
                      ],
                      "chain_recipe": {
                        "version": 1,
                        "canonicalization": "RFC8785",
                        "hash": "SHA-256",
                        "links": [
                          "policy",
                          "approval",
                          "payment",
                          "delivery"
                        ],
                        "signed_string": "nouron-receipt:v1:<receipt_id>:<chain>"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "public",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents": {
      "get": {
        "operationId": "listAgents",
        "summary": "Listar agentes",
        "description": "Los agentes del dueño (activos y archivados).",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de agentes.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListAgents"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      },
      "post": {
        "operationId": "createAgent",
        "summary": "Crear un agente",
        "description": "Nace con la lista de destinos VACÍA (no paga a nadie hasta que el dueño agregue) y SIN saldo propio: el saldo es de la bolsa comun. Máximo 5 agentes activos en prueba y 10 en real.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAgentRequest"
              },
              "examples": {
                "simple": {
                  "summary": "Solo nombre",
                  "value": {
                    "name": "Compras"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "El agente creado.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                },
                "examples": {
                  "agente": {
                    "summary": "Agente nuevo",
                    "value": {
                      "id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "object": "agent",
                      "name": "Compras",
                      "status": "active",
                      "livemode": false,
                      "policy_version": 4,
                      "created_at": "2026-10-08T09:00:00Z",
                      "paused_at": null,
                      "archived_at": null,
                      "request_id": "req_7y9u1iOp"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}": {
      "get": {
        "operationId": "getAgent",
        "summary": "Consultar un agente",
        "description": "Un agente del dueño.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "El agente.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      },
      "patch": {
        "operationId": "updateAgent",
        "summary": "Renombrar un agente",
        "description": "Solo el nombre. Las reglas se cambian con `PUT /v1/agents/{agent_id}/policy`.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAgentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El agente actualizado.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/pause": {
      "post": {
        "operationId": "pauseAgent",
        "summary": "Pausar un agente",
        "description": "Pausa de emergencia: desde ya todo pago nuevo se rechaza con `agent_paused`. Intenta anular lo aprobado y no enviado; el recibo lo registra. Pausar es facil; reanudar es más dificil.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "El agente, ya pausado (idempotente).",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/resume": {
      "post": {
        "operationId": "resumeAgent",
        "summary": "Reanudar un agente",
        "description": "Vuelve a permitir pagos. La consola puede exigir re-autenticación reciente; las llaves de dueño `read_only` no pueden.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "El agente, ya activo (idempotente).",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/archive": {
      "post": {
        "operationId": "archiveAgent",
        "summary": "Archivar un agente",
        "description": "Pasa por `archiving` (acepta liquidar, devolver y expirar lo que esta en vuelo) y luego a `archived` (se revocan sus llaves). Con retenciones o pagos sin liquidar responde 409 `agent_not_archivable`.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "El agente, en `archiving` o `archived`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/policy": {
      "get": {
        "operationId": "getAgentPolicy",
        "summary": "Reglas vigentes de un agente",
        "description": "La versión VIGENTE (no incluye cambios pendientes que aflojan).",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Reglas vigentes.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Policy"
                },
                "examples": {
                  "policy": {
                    "summary": "Version 4",
                    "value": {
                      "object": "policy",
                      "id": "pol_4a6c8e0b2d4f4a61b3d5f7a9c1e3b5d7",
                      "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                      "version": 4,
                      "hash": "sha256:ff8e18f66f66e5b1895a60fb25e71a4c8586612a53a9102b7cbf50e109d52116",
                      "per_spend_limit": "25.00",
                      "daily_cap": "100.00",
                      "monthly_cap": "500.00",
                      "lifetime_cap": null,
                      "allowed_destinations": [
                        "registry.npmjs.org",
                        "*.example.com"
                      ],
                      "trusted_destinations": [
                        "registry.npmjs.org",
                        "*.example.com"
                      ],
                      "blocked_destinations": [
                        "evil-pagos.example"
                      ],
                      "unknown_destination": "ask",
                      "approval_over": "20.00",
                      "destination_window_over": null,
                      "max_pending": 5,
                      "approval_ttl_minutes": 15,
                      "valid_until": null,
                      "paused": false,
                      "livemode": false,
                      "effective_at": "2026-10-08T09:00:00Z",
                      "created_at": "2026-10-08T09:00:00Z",
                      "request_id": "req_2r4t6yUi"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      },
      "put": {
        "operationId": "updateAgentPolicy",
        "summary": "Publicar una versión nueva de reglas",
        "description": "Crea una VERSIÓN NUEVA (las versiones no se editan). APRETAR (bajar un tope, quitar un destino) vale al instante y responde 200. AFLOJAR (subir un tope, agregar un destino, quitar la aprobación) espera 10 min en prueba o 24 h en real y responde 202 con un cambio `pending` que se puede cancelar. `expected_version` evita pisar un cambio ajeno (409 `policy_version_conflict`).",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Aplicada al instante (solo aprieta).",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyUpdateResult"
                }
              }
            }
          },
          "202": {
            "description": "Afloja: queda pendiente hasta `change.effective_at`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyUpdateResult"
                },
                "examples": {
                  "pendiente": {
                    "summary": "Sube el tope diario",
                    "value": {
                      "object": "policy_update",
                      "policy": {
                        "object": "policy",
                        "id": "pol_4a6c8e0b2d4f4a61b3d5f7a9c1e3b5d7",
                        "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                        "version": 4,
                        "hash": "sha256:ff8e18f66f66e5b1895a60fb25e71a4c8586612a53a9102b7cbf50e109d52116",
                        "per_spend_limit": "25.00",
                        "daily_cap": "100.00",
                        "monthly_cap": "500.00",
                        "lifetime_cap": null,
                        "allowed_destinations": [
                          "registry.npmjs.org",
                          "*.example.com"
                        ],
                        "trusted_destinations": [
                          "registry.npmjs.org",
                          "*.example.com"
                        ],
                        "blocked_destinations": [
                          "evil-pagos.example"
                        ],
                        "unknown_destination": "ask",
                        "approval_over": "20.00",
                        "destination_window_over": null,
                        "max_pending": 5,
                        "approval_ttl_minutes": 15,
                        "valid_until": null,
                        "paused": false,
                        "livemode": false,
                        "effective_at": "2026-10-08T09:00:00Z",
                        "created_at": "2026-10-08T09:00:00Z",
                        "request_id": "req_2r4t6yUi"
                      },
                      "change": {
                        "id": "chg_9c1e3a5b7d2f4a68b0d2f4a6c8e0b1d3",
                        "object": "policy_change",
                        "agent_id": "agt_3f7a2b9c4d1e8f60a5b7c3d2e1f09a84",
                        "kind": "loosening",
                        "status": "pending",
                        "from_version": 4,
                        "to_version": 5,
                        "loosened_fields": [
                          "daily_cap"
                        ],
                        "requested_at": "2026-10-09T15:00:00Z",
                        "effective_at": "2026-10-09T15:10:00Z",
                        "applied_at": null,
                        "cancelled_at": null,
                        "request_id": "req_8j9k1l2M"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/policy/versions": {
      "get": {
        "operationId": "listPolicyVersions",
        "summary": "Historial de versiónes de reglas",
        "description": "De la más nueva a la más antigua. Cada pago y cada recibo apuntan a una versión.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de versiónes.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListPolicies"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/destinations": {
      "get": {
        "operationId": "listDestinations",
        "summary": "Destinos permitidos",
        "description": "La lista de destinos de la versión vigente, más los pendientes de entrar en vigor.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de destinos.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListDestinations"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      },
      "post": {
        "operationId": "addDestination",
        "summary": "Permitir un destino",
        "description": "Agregar un destino AFLOJA las reglas: queda pendiente (202) 10 min en prueba o 24 h en real. Se rechazan los comodines sobre sufijos públicos (`*.vercel.app`, `*.github.io`...) con 422 y los destinos de la lista global de bloqueo.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddDestinationRequest"
              },
              "examples": {
                "npm": {
                  "summary": "Un dominio",
                  "value": {
                    "destination": "registry.npmjs.org",
                    "expected_version": 4
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ya vale (el destino ya estaba o el cambio no afloja).",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyUpdateResult"
                }
              }
            }
          },
          "202": {
            "description": "Pendiente hasta `change.effective_at`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyUpdateResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/destinations/{destination}": {
      "delete": {
        "operationId": "removeDestination",
        "summary": "Quitar un destino permitido",
        "description": "Quitar APRIETA las reglas: vale al instante.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/DestinationPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Reglas tras quitar el destino.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyUpdateResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/policy-changes": {
      "get": {
        "operationId": "listPolicyChanges",
        "summary": "Cambios de reglas",
        "description": "Incluye los que afloja y esperan. Filtra por `agent_id`.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          },
          {
            "$ref": "#/components/parameters/AgentIdFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de cambios.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListPolicyChanges"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/policy-changes/{change_id}/cancel": {
      "post": {
        "operationId": "cancelPolicyChange",
        "summary": "Cancelar un cambio pendiente (\"No fui yo\")",
        "description": "Cancela un cambio que afloja antes de que entre en vigor. Idempotente.",
        "tags": [
          "Administración del dueño"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/PolicyChangeIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "El cambio, ya cancelado.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PolicyChange"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/agents/{agent_id}/keys": {
      "get": {
        "operationId": "listKeys",
        "summary": "Listar llaves de un agente",
        "description": "Solo metadatos (prefijo, últimos 4, último uso, país). La llave completa NO se puede recuperar.",
        "tags": [
          "Llaves"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/StartingAfter"
          },
          {
            "$ref": "#/components/parameters/EndingBefore"
          }
        ],
        "responses": {
          "200": {
            "description": "Una página de llaves.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListKeys"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      },
      "post": {
        "operationId": "createKey",
        "summary": "Crear una llave de agente",
        "description": "Devuelve `secret` UNA SOLA VEZ. Guardala en una variable de entorno, nunca en un archivo del repositorio. Máximo 3 llaves activas por agente. Vence a los 90 días en prueba (30 en real) por defecto.",
        "tags": [
          "Llaves"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/AgentIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKeyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La llave, con `secret`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/keys/{key_id}/rotate": {
      "post": {
        "operationId": "rotateKey",
        "summary": "Rotar una llave con convivencia",
        "description": "Crea una llave nueva (`secret` una sola vez) y deja la vieja en `grace` hasta `grace_period_ends_at` (máximo 7 días; 0 la revoca ya). Así se cambia la llave del agente sin cortarlo.",
        "tags": [
          "Llaves"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/KeyIdPath"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotateKeyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "La llave nueva, con `secret`.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/keys/{key_id}/revoke": {
      "post": {
        "operationId": "revokeKey",
        "summary": "Revocar una llave",
        "description": "Irreversible e idempotente. Una llave revocada nunca vuelve a valer.",
        "tags": [
          "Llaves"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/KeyIdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "La llave, ya revocada.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/test/clock/advance": {
      "post": {
        "operationId": "advanceTestClock",
        "summary": "Adelantar el reloj de práctica",
        "description": "Vence aprobaciones (15 min), reinicia topes diarios y mensuales. SOLO con llave de prueba: con una llave real responde 404 `not_found` (la ruta no existe).",
        "tags": [
          "Sandbox (solo llaves de prueba)"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClockAdvanceRequest"
              },
              "examples": {
                "quince_minutos": {
                  "summary": "15 minutos",
                  "value": {
                    "seconds": 900
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El reloj de práctica.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestClock"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/test/reset": {
      "post": {
        "operationId": "resetTestEnvironment",
        "summary": "Reiniciar el entorno de práctica",
        "description": "Archiva los agentes de prueba y crea el entorno de nuevo con el saldo inicial como deposito \"Origen de práctica\". No purga el libro (opcion A de 24 5.4). Con llave real: 404.",
        "tags": [
          "Sandbox (solo llaves de prueba)"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "El entorno reiniciado.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestReset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "A1"
      }
    },
    "/v1/test/fund": {
      "post": {
        "operationId": "fundTestEnvironment",
        "summary": "Simular un deposito de práctica",
        "description": "Suma dinero de práctica. Tope de saldo 10.000 y 5 recargas al día. Con llave real: 404.",
        "tags": [
          "Sandbox (solo llaves de prueba)"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/OptionalIdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FundTestRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "El deposito simulado.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestFunding"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "C1"
      }
    },
    "/v1/test/events/{event_id}/redeliver": {
      "post": {
        "operationId": "redeliverTestEvent",
        "summary": "Reenviar un evento a los webhooks",
        "description": "Vuelve a entregar un evento a los destinos suscritos, en el orden pedido. Con llave real: 404.",
        "tags": [
          "Sandbox (solo llaves de prueba)"
        ],
        "security": [
          {
            "ownerKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/NouronVersion"
          },
          {
            "$ref": "#/components/parameters/EventIdPath"
          }
        ],
        "responses": {
          "202": {
            "description": "Reentrega encolada.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Nouron-Version": {
                "$ref": "#/components/headers/NouronVersion"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestRedelivery"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-nouron-audience": "owner",
        "x-nouron-milestone": "B2"
      }
    }
  },
  "webhooks": {
    "nouronEvent": {
      "post": {
        "operationId": "receiveNouronEvent",
        "summary": "Entrega de un evento (lo implementa TU servidor)",
        "description": "Nouron Pass hace un POST a tu destino de webhook por cada evento suscrito. Cada evento lleva `id` (evt_...), `sequence` (entero creciente por entorno: ordena y descarta los viejos) y se entrega al menos una vez: deduplica por `id`. Responde 2xx tras LEER la entrega (procesa después); cualquier otra respuesta o un tiempo de espera de 5 s se reintenta hasta 8 veces en ~24 h. Verifica la firma sobre el cuerpo CRUDO.",
        "tags": [
          "Eventos"
        ],
        "parameters": [
          {
            "name": "Nouron-Signature",
            "in": "header",
            "required": true,
            "description": "Firma t=<segundos>,v1=<hex>; tolerancia 300 s; durante una rotación llegan dos v1.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Nouron-Event-Id",
            "in": "header",
            "required": true,
            "description": "Id del evento (deduplica por este valor).",
            "schema": {
              "$ref": "#/components/schemas/EventId"
            }
          },
          {
            "name": "Nouron-Event",
            "in": "header",
            "required": true,
            "description": "Tipo del evento.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Nouron-Delivery",
            "in": "header",
            "required": true,
            "description": "Id de ESTE intento de entrega.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recibido (cualquier 2xx)."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "agentKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "np_<test|live>_agent_<38 caracteres>",
        "description": "Llave de AGENTE: la que se pega en el agente (cabecera o variable de entorno). Solo puede pagar, consultar y leer lo propio. Nunca administra nada."
      },
      "ownerKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "np_<test|live>_owner_<38 caracteres>",
        "description": "Llave de DUEÑO: administración (agentes, reglas, destinos, llaves). NUNCA se pega en un agente ni existe en el inicio rápido. No puede crear pagos ni decidir aprobaciones."
      }
    },
    "schemas": {
      "AgentId": {
        "type": "string",
        "pattern": "^agt_[0-9a-f]{32}$",
        "description": "Id de un agente. Forma: `agt_` + 32 hexadecimales en minusculas.",
        "examples": [
          "agt_0123456789abcdef0123456789abcdef"
        ]
      },
      "SpendId": {
        "type": "string",
        "pattern": "^spd_[0-9a-f]{32}$",
        "description": "Id de un pago. Forma: `spd_` + 32 hexadecimales en minusculas.",
        "examples": [
          "spd_0123456789abcdef0123456789abcdef"
        ]
      },
      "ApprovalId": {
        "type": "string",
        "pattern": "^apr_[0-9a-f]{32}$",
        "description": "Id de una aprobación. Forma: `apr_` + 32 hexadecimales en minusculas.",
        "examples": [
          "apr_0123456789abcdef0123456789abcdef"
        ]
      },
      "KeyId": {
        "type": "string",
        "pattern": "^key_[0-9a-f]{32}$",
        "description": "Id de una llave de API (no es la llave). Forma: `key_` + 32 hexadecimales en minusculas.",
        "examples": [
          "key_0123456789abcdef0123456789abcdef"
        ]
      },
      "PolicyId": {
        "type": "string",
        "pattern": "^pol_[0-9a-f]{32}$",
        "description": "Id de una versión de reglas. Forma: `pol_` + 32 hexadecimales en minusculas.",
        "examples": [
          "pol_0123456789abcdef0123456789abcdef"
        ]
      },
      "EventId": {
        "type": "string",
        "pattern": "^evt_[0-9a-f]{32}$",
        "description": "Id de un evento. Forma: `evt_` + 32 hexadecimales en minusculas.",
        "examples": [
          "evt_0123456789abcdef0123456789abcdef"
        ]
      },
      "ReceiptId": {
        "type": "string",
        "pattern": "^rcp_[0-9a-f]{32}$",
        "description": "Id de un recibo firmado. Forma: `rcp_` + 32 hexadecimales en minusculas.",
        "examples": [
          "rcp_0123456789abcdef0123456789abcdef"
        ]
      },
      "PolicyChangeId": {
        "type": "string",
        "pattern": "^chg_[0-9a-f]{32}$",
        "description": "Id de un cambio de reglas pendiente. Forma: `chg_` + 32 hexadecimales en minusculas.",
        "examples": [
          "chg_0123456789abcdef0123456789abcdef"
        ]
      },
      "Money": {
        "type": "string",
        "pattern": "^(0|[1-9][0-9]{0,11})(\\.[0-9]{1,6})?$",
        "description": "Monto como TEXTO decimal con hasta 6 decimales, nunca como número. \"0.001\" se conserva exacto; \"4.8\" sale como \"4.80\"."
      },
      "Currency": {
        "type": "string",
        "enum": [
          "usdc"
        ],
        "default": "usdc",
        "description": "En esta fase solo `usdc` (dólares digitales de práctica en prueba). Es explicito desde la v1 para no romper al agregar monedas.",
        "x-open-enum": true
      },
      "RequestId": {
        "type": "string",
        "pattern": "^req_[0-9A-Za-z]{8,32}$",
        "description": "Identificador de la petición (también en la cabecera `Request-Id`). Dalo a soporte.",
        "examples": [
          "req_6h1k9xQ2"
        ]
      },
      "NextAction": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "none",
              "wait_for_owner",
              "check_status_later",
              "ask_owner_to_add_destination",
              "ask_owner_to_raise_limit",
              "ask_owner_to_review",
              "retry_later",
              "retry_same_idempotency_key",
              "new_attempt_needs_new_key",
              "do_not_retry",
              "fix_request",
              "contact_support",
              "use_other_key_type",
              "verify_key",
              "complete_verification",
              "not_available_in_country"
            ],
            "description": "Qué hacer AHORA, en terminos de herramientas. Decide por el código, no por el texto. Lista ABIERTA: un código desconocido se trata como `contact_support`.",
            "x-open-enum": true
          },
          "check_with": {
            "type": "string",
            "enum": [
              "pass_get_spend",
              "pass_get_balance",
              "pass_get_policy",
              "pass_whoami"
            ],
            "description": "Herramienta MCP (o su ruta REST equivalente) con la que consultar."
          },
          "retry_after_seconds": {
            "type": "integer",
            "minimum": 0,
            "description": "Segundos antes de volver a consultar o a reintentar."
          },
          "owner_url": {
            "type": "string",
            "format": "uri",
            "description": "Página de la consola del dueño. Solo se abre con sesión de dueño; no sirve para aprobar desde la API."
          },
          "detail": {
            "type": "string",
            "maxLength": 300
          },
          "suggestions": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 200
            },
            "maxItems": 5
          }
        },
        "required": [
          "code"
        ]
      },
      "Rule": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "enum": [
              "agent_paused",
              "destination_not_allowed",
              "insufficient_balance",
              "per_spend_limit",
              "daily_cap",
              "monthly_cap",
              "lifetime_cap",
              "rolling_24h_cap",
              "permission_expired",
              "too_many_pending",
              "owner_declined",
              "price_above_max",
              "quote_mismatch",
              "rules_unavailable",
              "approval_incomplete",
              "approval_invalid",
              "unknown_destination_limit"
            ],
            "description": "Regla que se aplico."
          },
          "scope": {
            "type": "string",
            "enum": [
              "agent",
              "owner"
            ],
            "description": "agent = reglas de este agente; owner = tope por dueño / bolsa comun."
          },
          "limit": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,11})(\\.[0-9]{1,6})?$",
            "description": "Límite de la regla."
          },
          "spent": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,11})(\\.[0-9]{1,6})?$",
            "description": "Lo ya gastado o retenido dentro del límite."
          },
          "requested": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,11})(\\.[0-9]{1,6})?$",
            "description": "Lo que se pidió."
          },
          "remaining": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,11})(\\.[0-9]{1,6})?$",
            "description": "Lo que aun cabe."
          },
          "resets_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Cuando se reinicia el contador."
              },
              {
                "type": "null"
              }
            ]
          },
          "limit_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Solo en las reglas que cuentan cosas y no dinero (`too_many_pending`, `unknown_destination_limit`): el máximo permitido."
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Solo en esas mismas reglas: cuántos hay ya (por ejemplo, destinos nuevos pedidos hoy)."
          }
        },
        "required": [
          "name",
          "scope"
        ],
        "description": "Cifras de la regla que decidio. El motor solo devuelve el texto; el servicio calcula estos números."
      },
      "ErrorObject": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "invalid_request_error",
              "authentication_error",
              "permission_error",
              "rate_limit_error",
              "idempotency_error",
              "api_error"
            ],
            "description": "Familia del error. Lista ABIERTA: un tipo desconocido se trata por el estado HTTP.",
            "x-open-enum": true
          },
          "code": {
            "type": "string",
            "enum": [
              "invalid_json",
              "invalid_request",
              "missing_parameter",
              "unknown_parameter",
              "invalid_amount_format",
              "amount_not_positive",
              "unsupported_currency",
              "invalid_destination",
              "resource_required",
              "resource_not_allowed_for_address",
              "invalid_resource",
              "resource_host_mismatch",
              "invalid_memo",
              "invalid_client_reference",
              "missing_idempotency_key",
              "invalid_idempotency_key",
              "invalid_pagination",
              "invalid_filter",
              "unsupported_version",
              "invalid_policy",
              "payload_too_large",
              "missing_api_key",
              "invalid_api_key",
              "api_key_revoked",
              "api_key_expired",
              "permission_denied",
              "wrong_key_type",
              "read_only_key",
              "wrong_environment",
              "not_found",
              "idempotency_conflict",
              "idempotency_key_in_use",
              "cancel_too_late",
              "spend_not_cancellable",
              "policy_version_conflict",
              "agent_name_taken",
              "agent_not_archivable",
              "agent_limit_reached",
              "key_limit_reached",
              "quota_exceeded",
              "destination_wildcard_not_allowed",
              "destination_blocked",
              "policy_inconsistent",
              "agent_archived",
              "capability_unavailable",
              "verification_required",
              "account_on_hold",
              "rate_limited",
              "agent_busy",
              "internal_error",
              "service_unavailable",
              "platform_paused",
              "partner_unavailable"
            ],
            "description": "Código ESTABLE. El texto de `message` esta en español y puede cambiar. Lista ABIERTA: pueden aparecer códigos nuevos sin cambiar la versión; un código desconocido se trata por `status` y `retry`.",
            "x-open-enum": true
          },
          "message": {
            "type": "string",
            "maxLength": 500,
            "description": "Para personas. Nunca incluye la llave recibida."
          },
          "param": {
            "oneOf": [
              {
                "type": "string",
                "maxLength": 120,
                "description": "Campo culpable, con ruta con puntos (`resource.url`); null si no aplica."
              },
              {
                "type": "null"
              }
            ]
          },
          "retry": {
            "type": "string",
            "enum": [
              "no",
              "as_is",
              "after_fixing"
            ],
            "description": "`no` = no repitas. `as_is` = repite la MISMA petición tal cual (misma llave de idempotencia). `after_fixing` = corrige primero lo que dicen `message` y `param`, y entonces repite."
          },
          "retry_after_ms": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0,
                "description": "Espera mínima antes de repetir, en milisegundos (igual a `Retry-After` por 1000); null si no aplica."
              },
              {
                "type": "null"
              }
            ]
          },
          "outcome_unknown": {
            "type": "boolean",
            "description": "true = el pago PUDO haberse hecho aunque esta llamada falló. No repitas con otra llave: consulta el pago o repite igual con la MISMA llave de idempotencia."
          }
        },
        "required": [
          "type",
          "code",
          "message",
          "param",
          "retry",
          "retry_after_ms",
          "outcome_unknown"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "const": false
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599,
            "description": "El mismo estado HTTP de la respuesta (en MCP, el que le correspondería)."
          },
          "request_id": {
            "type": "string",
            "pattern": "^req_[0-9A-Za-z]{8,32}$",
            "description": "Igual a la cabecera `Request-Id`. Dalo a soporte."
          },
          "error": {
            "$ref": "#/components/schemas/ErrorObject"
          }
        },
        "required": [
          "ok",
          "status",
          "request_id",
          "error"
        ],
        "description": "Sobre de error ÚNICO (REST y MCP). Un RECHAZO POR REGLA no usa este sobre: es un `Spend` con `status: declined` y HTTP 2xx (D8)."
      },
      "ListSpends": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Spend"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Pagos, del más reciente al más antiguo."
      },
      "ListEvents": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Eventos de los últimos 30 días, del más reciente al más antiguo."
      },
      "ListAgents": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Agent"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Agentes del dueño."
      },
      "ListKeys": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKey"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Llaves del agente (nunca incluyen el secreto)."
      },
      "ListDestinations": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Destination"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Destinos permitidos de un agente."
      },
      "ListPolicies": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Policy"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Versiones de reglas, de la más nueva a la más antigua."
      },
      "ListPolicyChanges": {
        "type": "object",
        "properties": {
          "object": {
            "const": "list"
          },
          "url": {
            "type": "string"
          },
          "has_more": {
            "type": "boolean"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PolicyChange"
            }
          }
        },
        "required": [
          "object",
          "url",
          "has_more",
          "data"
        ],
        "description": "Cambios de reglas, del más reciente al más antiguo."
      },
      "MemoText": {
        "type": "string",
        "minLength": 1,
        "pattern": "^(?!\\s*$)[^\\p{Cc}\\p{Cf}]+$",
        "maxLength": 280,
        "description": "Frase del agente que explica el pago. DATO NO CONFIABLE: se muestra al dueño recortado, escapado y entre comillas como \"lo que dice el agente\"."
      },
      "Spend": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/SpendId"
          },
          "object": {
            "const": "spend"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "livemode": {
            "type": "boolean",
            "description": "false = dinero de práctica."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending_approval",
              "approved",
              "processing",
              "settled",
              "declined",
              "failed",
              "expired",
              "cancelled",
              "refunded",
              "disputed"
            ],
            "x-open-enum": false
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "amount_settled": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "destination": {
            "type": "string",
            "maxLength": 253,
            "description": "Destino ya normalizado."
          },
          "destination_rule": {
            "oneOf": [
              {
                "type": "string",
                "description": "Regla de la lista que autorizo el pago (host o patron)."
              },
              {
                "type": "null"
              }
            ]
          },
          "resource": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "host": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "GET",
                      "POST"
                    ]
                  }
                },
                "required": [
                  "host",
                  "path",
                  "method"
                ],
                "description": "Qué se compró (sin cuerpo ni consulta). null en una transferencia a dirección 0x."
              },
              {
                "type": "null"
              }
            ]
          },
          "memo": {
            "$ref": "#/components/schemas/MemoText"
          },
          "client_reference": {
            "oneOf": [
              {
                "type": "string",
                "maxLength": 64,
                "pattern": "^[A-Za-z0-9._:-]{1,64}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "policy_version": {
            "type": "integer",
            "minimum": 1,
            "description": "Versión de reglas con la que se evaluo por última vez."
          },
          "decline_reason": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "agent_paused",
                  "destination_not_allowed",
                  "insufficient_balance",
                  "per_spend_limit",
                  "daily_cap",
                  "monthly_cap",
                  "lifetime_cap",
                  "rolling_24h_cap",
                  "permission_expired",
                  "too_many_pending",
                  "owner_declined",
                  "price_above_max",
                  "quote_mismatch",
                  "rules_unavailable",
                  "approval_incomplete",
                  "approval_invalid",
                  "unknown_destination_limit"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "declined_at_gate": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "create",
                  "approval",
                  "execute"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "pause_detail": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "paused",
                  "owner_emergency_pause",
                  "platform_emergency_pause",
                  "status_unreadable",
                  "key_revoked"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "approval_reason": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "approval_over",
                  "destination_window",
                  "history_incomplete",
                  "dual_approval",
                  "possible_duplicate",
                  "new_destination",
                  "outside_hours",
                  "max_per_destination_24h",
                  "approval_changed",
                  "payto_changed",
                  "unknown_destination",
                  "sandbox_magic_amount"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "approval": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "$ref": "#/components/schemas/ApprovalId"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "pending",
                      "approved",
                      "rejected",
                      "expired",
                      "cancelled"
                    ]
                  },
                  "expires_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "items_hash": {
                    "type": "string",
                    "pattern": "^sha256:[0-9a-f]{64}$",
                    "description": "Huella de lo que se aprobó (monto máximo, moneda, destino, recurso). Si cambia antes de enviar, vuelve a pedir."
                  },
                  "short_code": {
                    "type": "string",
                    "pattern": "^#[0-9A-Z]{4}$",
                    "description": "Código de 4 caracteres que el dueño compara con su aviso (24 3 #15)."
                  },
                  "owner_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Página de la consola. No sirve para aprobar sin sesión de dueño."
                  }
                },
                "required": [
                  "id",
                  "status",
                  "expires_at",
                  "items_hash",
                  "short_code",
                  "owner_url"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "hold": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "amount": {
                    "$ref": "#/components/schemas/Money"
                  },
                  "expires_at": {
                    "oneOf": [
                      {
                        "type": "string",
                        "format": "date-time",
                        "description": "null = sin vencimiento (un `processing` incierto no libera el cupo solo)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "amount",
                  "expires_at"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "settlement": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "pass_executes_x402",
                      "pass_executes_transfer"
                    ],
                    "description": "En la fase 1 Pass paga por el agente; el agente nunca recibe credencial ni firma."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "processing",
                      "settled",
                      "failed"
                    ]
                  },
                  "network": {
                    "oneOf": [
                      {
                        "type": "string",
                        "description": "Red del pago, por ejemplo base-sepolia (práctica)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "reference": {
                    "oneOf": [
                      {
                        "type": "string",
                        "description": "Referencia externa (hash de la transaccion)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "receipt_id": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/ReceiptId"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "result": {
                    "oneOf": [
                      {
                        "$ref": "#/components/schemas/SettlementResult"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "mode",
                  "status",
                  "receipt_id"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "failure_reason": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "rail_error",
                  "vendor_error",
                  "delivery_failed"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "rail_error": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "pattern": "^[a-z_]{1,40}$"
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 300,
                    "description": "Textual del riel (no se traduce ni se resume)."
                  }
                },
                "required": [
                  "code",
                  "message"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "processing_detail": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "enum": [
                      "awaiting_settlement",
                      "outcome_unknown"
                    ],
                    "description": "`outcome_unknown` = el dinero pudo haberse movido: NO repetir con otra llave. `awaiting_settlement` = el riel acepto y confirma luego."
                  },
                  "message": {
                    "type": "string",
                    "maxLength": 300
                  },
                  "since": {
                    "type": "string",
                    "format": "date-time"
                  }
                },
                "required": [
                  "code",
                  "message",
                  "since"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "rule": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Rule"
              },
              {
                "type": "null"
              }
            ]
          },
          "sandbox": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "forced": {
                    "type": "string",
                    "enum": [
                      "magic_amount"
                    ],
                    "description": "El resultado lo forzo un monto mágico, NO las reglas del usuario."
                  },
                  "simulated_vendor": {
                    "type": "boolean",
                    "description": "El vendedor es el \"pueblo de prueba\" de Pass."
                  }
                },
                "required": [],
                "description": "Solo con llaves de prueba. null en el entorno real."
              },
              {
                "type": "null"
              }
            ]
          },
          "message": {
            "type": "string",
            "maxLength": 500,
            "description": "Una frase para la persona y el modelo. Decide por los códigos, no por este texto."
          },
          "next_action": {
            "$ref": "#/components/schemas/NextAction"
          },
          "retryable": {
            "type": "boolean"
          },
          "idempotent_replay": {
            "type": "boolean",
            "description": "true = es el estado ACTUAL del mismo pago, devuelto por repetir la llave de idempotencia."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "id",
          "object",
          "agent_id",
          "livemode",
          "status",
          "amount",
          "amount_settled",
          "currency",
          "destination",
          "destination_rule",
          "resource",
          "memo",
          "client_reference",
          "policy_version",
          "decline_reason",
          "declined_at_gate",
          "pause_detail",
          "approval_reason",
          "approval",
          "hold",
          "settlement",
          "failure_reason",
          "rail_error",
          "processing_detail",
          "rule",
          "sandbox",
          "message",
          "next_action",
          "retryable",
          "idempotent_replay",
          "created_at",
          "updated_at",
          "request_id"
        ],
        "description": "Un pago. `status` dice donde esta; `approved` NO significa pagado: el pago salio solo con `settled`. `amount` es el MÁXIMO que el agente acepta; el precio lo fija el vendedor (`amount_settled`). Todas las claves estan siempre presentes (null cuando no aplican).",
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "declined"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "decline_reason": {
                  "not": {
                    "type": "null"
                  }
                },
                "declined_at_gate": {
                  "not": {
                    "type": "null"
                  }
                },
                "approval_reason": {
                  "type": "null"
                },
                "hold": {
                  "type": "null"
                },
                "settlement": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "decline_reason",
                "declined_at_gate",
                "approval_reason",
                "hold",
                "settlement",
                "failure_reason",
                "rail_error",
                "processing_detail",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "pending_approval"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "approval": {
                  "not": {
                    "type": "null"
                  }
                },
                "approval_reason": {
                  "not": {
                    "type": "null"
                  }
                },
                "hold": {
                  "not": {
                    "type": "null"
                  }
                },
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "settlement": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "approval",
                "approval_reason",
                "hold",
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "settlement",
                "failure_reason",
                "rail_error",
                "processing_detail",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "approved"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "hold": {
                  "not": {
                    "type": "null"
                  }
                },
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "settlement": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "hold",
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "settlement",
                "failure_reason",
                "rail_error",
                "processing_detail",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "processing"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "hold": {
                  "not": {
                    "type": "null"
                  }
                },
                "settlement": {
                  "not": {
                    "type": "null"
                  },
                  "properties": {
                    "status": {
                      "const": "processing"
                    }
                  },
                  "required": [
                    "status"
                  ]
                },
                "processing_detail": {
                  "not": {
                    "type": "null"
                  }
                },
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "hold",
                "settlement",
                "processing_detail",
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "failure_reason",
                "rail_error",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "settled"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "amount_settled": {
                  "not": {
                    "type": "null"
                  }
                },
                "settlement": {
                  "not": {
                    "type": "null"
                  },
                  "properties": {
                    "status": {
                      "const": "settled"
                    },
                    "receipt_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "status",
                    "receipt_id"
                  ]
                },
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "hold": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                }
              },
              "required": [
                "amount_settled",
                "settlement",
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "hold",
                "failure_reason",
                "rail_error",
                "processing_detail"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "failed"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "failure_reason": {
                  "not": {
                    "type": "null"
                  }
                },
                "settlement": {
                  "not": {
                    "type": "null"
                  },
                  "properties": {
                    "status": {
                      "const": "failed"
                    }
                  },
                  "required": [
                    "status"
                  ]
                },
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "hold": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "failure_reason",
                "settlement",
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "hold",
                "processing_detail",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "expired"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "hold": {
                  "type": "null"
                },
                "settlement": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "hold",
                "settlement",
                "failure_reason",
                "rail_error",
                "processing_detail",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "cancelled"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "decline_reason": {
                  "type": "null"
                },
                "declined_at_gate": {
                  "type": "null"
                },
                "pause_detail": {
                  "type": "null"
                },
                "hold": {
                  "type": "null"
                },
                "settlement": {
                  "type": "null"
                },
                "failure_reason": {
                  "type": "null"
                },
                "rail_error": {
                  "type": "null"
                },
                "processing_detail": {
                  "type": "null"
                },
                "amount_settled": {
                  "type": "null"
                }
              },
              "required": [
                "decline_reason",
                "declined_at_gate",
                "pause_detail",
                "hold",
                "settlement",
                "failure_reason",
                "rail_error",
                "processing_detail",
                "amount_settled"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "pause_detail": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "pause_detail"
              ]
            },
            "then": {
              "properties": {
                "decline_reason": {
                  "const": "agent_paused"
                }
              },
              "required": [
                "decline_reason"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "decline_reason": {
                  "const": "agent_paused"
                }
              },
              "required": [
                "decline_reason"
              ]
            },
            "then": {
              "properties": {
                "pause_detail": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "pause_detail"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "processing_detail": {
                  "not": {
                    "type": "null"
                  },
                  "properties": {
                    "code": {
                      "const": "outcome_unknown"
                    }
                  },
                  "required": [
                    "code"
                  ]
                }
              },
              "required": [
                "processing_detail"
              ]
            },
            "then": {
              "properties": {
                "hold": {
                  "properties": {
                    "expires_at": {
                      "type": "null"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "SettlementResult": {
        "type": "object",
        "properties": {
          "http_status": {
            "type": "integer",
            "minimum": 100,
            "maximum": 599
          },
          "content_type": {
            "type": "string",
            "maxLength": 120
          },
          "body": {
            "type": "string",
            "maxLength": 20000,
            "description": "Respuesta del vendedor, recortada. DATO NO CONFIABLE de un tercero."
          },
          "body_truncated": {
            "type": "boolean"
          },
          "body_sha256": {
            "type": "string",
            "pattern": "^sha256:[0-9a-f]{64}$"
          }
        },
        "required": [
          "http_status",
          "content_type",
          "body",
          "body_truncated",
          "body_sha256"
        ]
      },
      "Approval": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/ApprovalId"
          },
          "object": {
            "const": "approval"
          },
          "spend_id": {
            "$ref": "#/components/schemas/SpendId"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "livemode": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected",
              "expired",
              "cancelled"
            ]
          },
          "reason": {
            "type": "string",
            "enum": [
              "approval_over",
              "destination_window",
              "history_incomplete",
              "dual_approval",
              "possible_duplicate",
              "new_destination",
              "outside_hours",
              "max_per_destination_24h",
              "approval_changed",
              "payto_changed",
              "unknown_destination",
              "sandbox_magic_amount"
            ]
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "destination": {
            "type": "string",
            "maxLength": 253
          },
          "resource": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "host": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "GET",
                      "POST"
                    ]
                  }
                },
                "required": [
                  "host",
                  "path",
                  "method"
                ],
                "description": "Qué se compró (sin cuerpo ni consulta). null en una transferencia a dirección 0x."
              },
              {
                "type": "null"
              }
            ]
          },
          "memo": {
            "$ref": "#/components/schemas/MemoText"
          },
          "items_hash": {
            "type": "string",
            "pattern": "^sha256:[0-9a-f]{64}$"
          },
          "short_code": {
            "type": "string",
            "pattern": "^#[0-9A-Z]{4}$",
            "description": "Código de 4 caracteres que el dueño compara con su aviso (24 3 #15)."
          },
          "owner_url": {
            "type": "string",
            "format": "uri"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "decided_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "decided_via": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "panel",
                  "telegram",
                  "email",
                  "whatsapp",
                  "system"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "id",
          "object",
          "spend_id",
          "agent_id",
          "livemode",
          "status",
          "reason",
          "amount",
          "currency",
          "destination",
          "resource",
          "memo",
          "items_hash",
          "short_code",
          "owner_url",
          "created_at",
          "expires_at",
          "decided_at",
          "decided_via",
          "request_id"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "pending"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "decided_at": {
                  "type": "null"
                },
                "decided_via": {
                  "type": "null"
                }
              },
              "required": [
                "decided_at",
                "decided_via"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "approved"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "decided_at": {
                  "not": {
                    "type": "null"
                  }
                },
                "decided_via": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "decided_at",
                "decided_via"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "rejected"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "decided_at": {
                  "not": {
                    "type": "null"
                  }
                },
                "decided_via": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "decided_at",
                "decided_via"
              ]
            }
          }
        ],
        "description": "Aprobación pendiente o decidida. SOLO se lee: aprobar exige SIEMPRE la sesión del dueño (consola, Telegram, correo, WhatsApp con enlace firmado); no existe endpoint de API para decidir."
      },
      "Receipt": {
        "type": "object",
        "properties": {
          "object": {
            "const": "receipt"
          },
          "receipt_id": {
            "$ref": "#/components/schemas/ReceiptId"
          },
          "receipt_version": {
            "type": "integer",
            "enum": [
              1,
              2
            ],
            "x-open-enum": true,
            "description": "Versión del formato del recibo (lista ABIERTA: pueden aparecer versiones nuevas).. 1 = `payment.rail` siempre `x402`. 2 = `payment.rail` puede ser otro riel (lista abierta). Los recibos de la versión 1 se siguen verificando igual."
          },
          "spend_id": {
            "$ref": "#/components/schemas/SpendId"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "livemode": {
            "type": "boolean"
          },
          "policy": {
            "type": "object",
            "properties": {
              "version": {
                "type": "integer",
                "minimum": 1
              },
              "hash": {
                "type": "string",
                "pattern": "^sha256:[0-9a-f]{64}$"
              }
            },
            "required": [
              "version",
              "hash"
            ],
            "description": "Foto inmutable de las reglas vigentes al decidir (O-140)."
          },
          "approval": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "auto",
                  "owner"
                ]
              },
              "items_hash": {
                "type": "string",
                "pattern": "^sha256:[0-9a-f]{64}$"
              },
              "approved_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "mode",
              "items_hash",
              "approved_at"
            ]
          },
          "payment": {
            "type": "object",
            "properties": {
              "rail": {
                "type": "string",
                "enum": [
                  "x402",
                  "transfer"
                ],
                "description": "Riel de pago. En recibos versión 1 es siempre `x402`; desde la versión 2 es una lista ABIERTA: un riel desconocido no invalida el recibo.",
                "x-open-enum": true
              },
              "network": {
                "type": "string"
              },
              "reference": {
                "type": "string"
              },
              "amount": {
                "$ref": "#/components/schemas/Money"
              },
              "currency": {
                "$ref": "#/components/schemas/Currency"
              },
              "destination": {
                "type": "string"
              },
              "attempt_id": {
                "type": "string",
                "pattern": "^att_[0-9a-f]{32}$"
              },
              "money_moved": {
                "type": "boolean",
                "description": "false en práctica."
              },
              "sandbox": {
                "type": "boolean"
              },
              "at": {
                "type": "string",
                "format": "date-time"
              },
              "external": {
                "type": "object",
                "properties": {
                  "network_caip2": {
                    "type": "string",
                    "pattern": "^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}$"
                  },
                  "transaction": {
                    "type": "string"
                  },
                  "facilitator_id": {
                    "type": "string"
                  },
                  "vendor_receipt_sha256": {
                    "type": "string",
                    "pattern": "^sha256:[0-9a-f]{64}$"
                  }
                },
                "required": [],
                "description": "Referencias externas guardadas tal cual (CAIP-2, hash, id del facilitador). O-140."
              }
            },
            "required": [
              "rail",
              "network",
              "reference",
              "amount",
              "currency",
              "destination",
              "attempt_id",
              "money_moved",
              "sandbox",
              "at"
            ]
          },
          "delivery": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "http_status": {
                    "type": "integer"
                  },
                  "body_sha256": {
                    "type": "string",
                    "pattern": "^sha256:[0-9a-f]{64}$"
                  }
                },
                "required": [
                  "http_status",
                  "body_sha256"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "chain_version": {
            "type": "integer",
            "enum": [
              1,
              2
            ],
            "x-open-enum": true,
            "description": "Versión de la receta de la cadena; viaja DENTRO de la cadena. Igual a `receipt_version`."
          },
          "chain": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "SHA-256 de JCS(RFC 8785) de { v, links: [policy, approval, payment, delivery] }."
          },
          "sig": {
            "type": "object",
            "properties": {
              "alg": {
                "const": "Ed25519"
              },
              "kid": {
                "type": "string",
                "maxLength": 120,
                "description": "Identificador de la llave pública en /.well-known/nouron-pass-receipt-keys.json."
              },
              "value": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{86}$",
                "description": "Ed25519 en base64url sobre `nouron-receipt:v1:<receipt_id>:<chain>`."
              }
            },
            "required": [
              "alg",
              "kid",
              "value"
            ]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "receipt_id",
          "receipt_version",
          "spend_id",
          "agent_id",
          "livemode",
          "policy",
          "approval",
          "payment",
          "delivery",
          "chain_version",
          "chain",
          "sig",
          "request_id"
        ],
        "description": "Recibo firmado de Pass (27 C.5). Se verifica con un archivo y `node:crypto`; 9 veredictos (27 E.6).",
        "allOf": [
          {
            "if": {
              "properties": {
                "livemode": {
                  "const": false
                }
              },
              "required": [
                "livemode"
              ]
            },
            "then": {
              "properties": {
                "payment": {
                  "properties": {
                    "money_moved": {
                      "const": false
                    },
                    "sandbox": {
                      "const": true
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "ReceiptKeys": {
        "type": "object",
        "properties": {
          "object": {
            "const": "receipt_keys"
          },
          "keys": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kid": {
                  "type": "string"
                },
                "alg": {
                  "const": "Ed25519"
                },
                "x": {
                  "type": "string",
                  "pattern": "^[A-Za-z0-9_-]{43}$",
                  "description": "Llave pública Ed25519 en base64url (JWK `x`)."
                },
                "environment": {
                  "type": "string",
                  "enum": [
                    "test",
                    "live"
                  ],
                  "description": "Espacios de llaves SEPARADOS: un recibo de práctica verificado con una llave live da `unknown_key`."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "retired"
                  ],
                  "description": "Rotar RETIRA, no revoca: una llave retirada sigue publicada."
                },
                "not_before": {
                  "type": "string",
                  "format": "date-time"
                },
                "retired_at": {
                  "oneOf": [
                    {
                      "type": "string",
                      "format": "date-time"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "kid",
                "alg",
                "x",
                "environment",
                "status",
                "not_before",
                "retired_at"
              ]
            }
          },
          "chain_recipe": {
            "type": "object",
            "properties": {
              "version": {
                "type": "integer",
                "minimum": 1
              },
              "canonicalization": {
                "const": "RFC8785"
              },
              "hash": {
                "const": "SHA-256"
              },
              "links": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "policy",
                    "approval",
                    "payment",
                    "delivery"
                  ]
                }
              },
              "signed_string": {
                "type": "string",
                "description": "Plantilla del texto que se firma."
              }
            },
            "required": [
              "version",
              "canonicalization",
              "hash",
              "links",
              "signed_string"
            ],
            "description": "La receta como DATO: un verificador antiguo no adivina el orden."
          }
        },
        "required": [
          "object",
          "keys",
          "chain_recipe"
        ]
      },
      "CreateSpendRequest": {
        "type": "object",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "destination": {
            "type": "string",
            "maxLength": 253,
            "description": "Dominio del vendedor (`api.openai.com`) o dirección 0x. Sin `https://` ni ruta ni comodín."
          },
          "resource": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "maxLength": 2048,
                "description": "https://..., mismo host que `destination`, sin redirecciones."
              },
              "method": {
                "type": "string",
                "enum": [
                  "GET",
                  "POST"
                ],
                "default": "GET"
              },
              "body": {
                "type": "string",
                "maxLength": 8192,
                "description": "Cuerpo como texto; solo con POST."
              }
            },
            "required": [
              "url"
            ],
            "additionalProperties": false,
            "description": "OBLIGATORIO si `destination` es un dominio (`resource_required`); PROHIBIDO si es una dirección 0x. Pass pide el recurso, recibe el 402 y paga: el agente nunca ve la firma."
          },
          "memo": {
            "$ref": "#/components/schemas/MemoText"
          },
          "client_reference": {
            "type": "string",
            "pattern": "^[A-Za-z0-9._:-]{1,64}$",
            "minLength": 1,
            "maxLength": 64,
            "description": "Tu id de tarea, para conciliar. No entra en la huella de idempotencia."
          }
        },
        "required": [
          "amount",
          "destination",
          "memo"
        ],
        "additionalProperties": false,
        "description": "`amount` es el MÁXIMO que el agente acepta pagar. La llave de idempotencia va en la cabecera `Idempotency-Key` (en MCP es el argumento `idempotency_key`)."
      },
      "CheckSpendRequest": {
        "type": "object",
        "properties": {
          "destination": {
            "type": "string",
            "maxLength": 253
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          }
        },
        "required": [
          "destination"
        ],
        "additionalProperties": false,
        "description": "Sin `amount` solo comprueba el destino (cumple el papel de `check_destination` de la v0). No reserva nada ni crea pagos."
      },
      "SpendCheck": {
        "type": "object",
        "properties": {
          "object": {
            "const": "spend_check"
          },
          "allowed": {
            "type": "boolean",
            "description": "true si el destino pasa y, con `amount`, la decisión seria aprobar."
          },
          "destination": {
            "type": "string"
          },
          "decision": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "approved",
                  "pending_approval",
                  "declined"
                ],
                "description": "null si no se mando `amount` (solo destino)."
              },
              {
                "type": "null"
              }
            ]
          },
          "reason": {
            "oneOf": [
              {
                "type": "string",
                "description": "Un `decline_reason` o un `approval_reason`."
              },
              {
                "type": "null"
              }
            ]
          },
          "matched_rule": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "rule": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Rule"
              },
              {
                "type": "null"
              }
            ]
          },
          "reserves_nothing": {
            "const": true
          },
          "message": {
            "type": "string",
            "maxLength": 500
          },
          "next_action": {
            "$ref": "#/components/schemas/NextAction"
          },
          "livemode": {
            "type": "boolean"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "allowed",
          "destination",
          "decision",
          "reason",
          "matched_rule",
          "rule",
          "reserves_nothing",
          "message",
          "next_action",
          "livemode",
          "request_id"
        ],
        "description": "Simulación completa contra el motor, sin crear nada. Puede quedar obsoleta un segundo después."
      },
      "Balance": {
        "type": "object",
        "properties": {
          "object": {
            "const": "balance"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "spendable": {
            "$ref": "#/components/schemas/Money"
          },
          "limiting_factor": {
            "type": "string",
            "enum": [
              "pool_available",
              "daily_remaining",
              "monthly_remaining",
              "per_spend_limit",
              "lifetime_remaining"
            ]
          },
          "components": {
            "type": "object",
            "properties": {
              "pool_available": {
                "$ref": "#/components/schemas/Money"
              },
              "reserve_floor": {
                "$ref": "#/components/schemas/Money"
              },
              "daily_remaining": {
                "$ref": "#/components/schemas/Money"
              },
              "monthly_remaining": {
                "$ref": "#/components/schemas/Money"
              },
              "per_spend_limit": {
                "$ref": "#/components/schemas/Money"
              },
              "lifetime_remaining": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "pool_available",
              "reserve_floor",
              "daily_remaining",
              "monthly_remaining",
              "per_spend_limit",
              "lifetime_remaining"
            ],
            "description": "`spendable` = el MENOR de: (pool_available - reserve_floor), daily_remaining, monthly_remaining, per_spend_limit y lifetime_remaining si existe (O-87). Nunca negativo."
          },
          "held": {
            "$ref": "#/components/schemas/Money"
          },
          "pending_count": {
            "type": "integer",
            "minimum": 0
          },
          "message": {
            "type": "string",
            "maxLength": 300
          },
          "livemode": {
            "type": "boolean"
          },
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "agent_id",
          "currency",
          "spendable",
          "limiting_factor",
          "components",
          "held",
          "pending_count",
          "message",
          "livemode",
          "as_of",
          "request_id"
        ],
        "description": "Cuánto puede gastar ESTE agente ahora mismo, y por qué. En práctica el mensaje dice \"(dinero de práctica)\"."
      },
      "Agent": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "object": {
            "const": "agent"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "archiving",
              "archived"
            ],
            "description": "`archiving` acepta liquidar, devolver y expirar lo que esta en vuelo; después pasa a `archived` y se revocan sus llaves."
          },
          "livemode": {
            "type": "boolean"
          },
          "policy_version": {
            "type": "integer",
            "minimum": 1
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "paused_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "archived_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "id",
          "object",
          "name",
          "status",
          "livemode",
          "policy_version",
          "created_at",
          "paused_at",
          "archived_at",
          "request_id"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "active"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "paused_at": {
                  "type": "null"
                },
                "archived_at": {
                  "type": "null"
                }
              },
              "required": [
                "paused_at",
                "archived_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "paused"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "paused_at": {
                  "not": {
                    "type": "null"
                  }
                },
                "archived_at": {
                  "type": "null"
                }
              },
              "required": [
                "paused_at",
                "archived_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "archiving"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "archived_at": {
                  "type": "null"
                }
              },
              "required": [
                "archived_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "archived"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "archived_at": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "archived_at"
              ]
            }
          }
        ]
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/KeyId"
          },
          "object": {
            "const": "api_key"
          },
          "kind": {
            "type": "string",
            "enum": [
              "agent",
              "owner"
            ],
            "description": "`agent` se pega en un agente; `owner` administra y NUNCA se pega en un agente."
          },
          "agent_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AgentId"
              },
              {
                "type": "null"
              }
            ]
          },
          "livemode": {
            "type": "boolean"
          },
          "prefix": {
            "type": "string",
            "pattern": "^np_(test|live)_(agent|owner)_$",
            "description": "Prefijo de la llave. La llave completa NO se puede recuperar."
          },
          "last4": {
            "type": "string",
            "pattern": "^[A-Za-z0-9]{4}$"
          },
          "scope": {
            "type": "string",
            "enum": [
              "full",
              "read_only"
            ],
            "description": "`read_only` no puede crear pagos ni escribir."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "grace",
              "revoked",
              "expired"
            ],
            "description": "`grace` = reemplazada por una rotación; sigue valiendo hasta `grace_period_ends_at` (máximo 7 días)."
          },
          "api_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
            "description": "Versión de la API fijada a esta llave."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Vencimiento (90 días por defecto en prueba, 30 en real). Nunca \"sin vencimiento\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "last_used_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_used_country": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "revoked_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "rotated_from": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/KeyId"
              },
              {
                "type": "null"
              }
            ]
          },
          "grace_period_ends_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "id",
          "object",
          "kind",
          "agent_id",
          "livemode",
          "prefix",
          "last4",
          "scope",
          "status",
          "api_version",
          "created_at",
          "expires_at",
          "last_used_at",
          "last_used_country",
          "revoked_at",
          "rotated_from",
          "grace_period_ends_at",
          "request_id"
        ],
        "description": "Metadatos de una llave. NUNCA lleva el secreto: eso es `ApiKeyCreated`, solo al crear o rotar.",
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "revoked"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "revoked_at": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "revoked_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "grace"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "grace_period_ends_at": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "grace_period_ends_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "owner"
                }
              },
              "required": [
                "kind"
              ]
            },
            "then": {
              "properties": {
                "agent_id": {
                  "type": "null"
                }
              },
              "required": [
                "agent_id"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "agent"
                }
              },
              "required": [
                "kind"
              ]
            },
            "then": {
              "properties": {
                "agent_id": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "agent_id"
              ]
            }
          }
        ]
      },
      "ApiKeyCreated": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/KeyId"
          },
          "object": {
            "const": "api_key"
          },
          "kind": {
            "type": "string",
            "enum": [
              "agent",
              "owner"
            ],
            "description": "`agent` se pega en un agente; `owner` administra y NUNCA se pega en un agente."
          },
          "agent_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AgentId"
              },
              {
                "type": "null"
              }
            ]
          },
          "livemode": {
            "type": "boolean"
          },
          "prefix": {
            "type": "string",
            "pattern": "^np_(test|live)_(agent|owner)_$",
            "description": "Prefijo de la llave. La llave completa NO se puede recuperar."
          },
          "last4": {
            "type": "string",
            "pattern": "^[A-Za-z0-9]{4}$"
          },
          "scope": {
            "type": "string",
            "enum": [
              "full",
              "read_only"
            ],
            "description": "`read_only` no puede crear pagos ni escribir."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "grace",
              "revoked",
              "expired"
            ],
            "description": "`grace` = reemplazada por una rotación; sigue valiendo hasta `grace_period_ends_at` (máximo 7 días)."
          },
          "api_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
            "description": "Versión de la API fijada a esta llave."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Vencimiento (90 días por defecto en prueba, 30 en real). Nunca \"sin vencimiento\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "last_used_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_used_country": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^[A-Z]{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "revoked_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "rotated_from": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/KeyId"
              },
              {
                "type": "null"
              }
            ]
          },
          "grace_period_ends_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          },
          "secret": {
            "type": "string",
            "pattern": "^np_(test|live)_(agent|owner)_[A-Za-z0-9]{38}$",
            "description": "La llave completa. SOLO aparece en la respuesta que la crea o la rota, una única vez. Guárdala en una variable de entorno, nunca en un archivo del repositorio."
          }
        },
        "required": [
          "id",
          "object",
          "kind",
          "agent_id",
          "livemode",
          "prefix",
          "last4",
          "scope",
          "status",
          "api_version",
          "created_at",
          "expires_at",
          "last_used_at",
          "last_used_country",
          "revoked_at",
          "rotated_from",
          "grace_period_ends_at",
          "request_id",
          "secret"
        ],
        "description": "Respuesta de crear o rotar una llave: metadatos más el secreto, que no se vuelve a mostrar.",
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "revoked"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "revoked_at": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "revoked_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "grace"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "grace_period_ends_at": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "grace_period_ends_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "owner"
                }
              },
              "required": [
                "kind"
              ]
            },
            "then": {
              "properties": {
                "agent_id": {
                  "type": "null"
                }
              },
              "required": [
                "agent_id"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "agent"
                }
              },
              "required": [
                "kind"
              ]
            },
            "then": {
              "properties": {
                "agent_id": {
                  "not": {
                    "type": "null"
                  }
                }
              },
              "required": [
                "agent_id"
              ]
            }
          }
        ]
      },
      "Policy": {
        "type": "object",
        "properties": {
          "object": {
            "const": "policy"
          },
          "id": {
            "$ref": "#/components/schemas/PolicyId"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "hash": {
            "type": "string",
            "pattern": "^sha256:[0-9a-f]{64}$",
            "description": "Huella de esta versión; viaja en el recibo."
          },
          "per_spend_limit": {
            "$ref": "#/components/schemas/Money"
          },
          "daily_cap": {
            "$ref": "#/components/schemas/Money"
          },
          "monthly_cap": {
            "$ref": "#/components/schemas/Money"
          },
          "lifetime_cap": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "allowed_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "ALIAS de `trusted_destinations` (el nombre de antes de R-177; mismo contenido). Hosts, comodines de UN nivel (`*.ejemplo.com`) o direcciones 0x. Si mandas las dos listas deben ser iguales (si no, 400 `invalid_request`). Con `unknown_destination: block`, vacía = no pasa nada. Prohibidos los comodines sobre sufijos públicos."
          },
          "trusted_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "Destinos de confianza: el agente les paga sin preguntar (dentro de los topes). Hosts, comodines de UN nivel (`*.ejemplo.com`) o direcciones 0x. Con `unknown_destination: ask` puede estar vacía. Confiar en un destino NUEVO afloja las reglas: espera 10 min en prueba y 24 h en real."
          },
          "blocked_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "Destinos bloqueados: se rechazan SIEMPRE (`destination_not_allowed`). Ganan sobre los de confianza y el sí del dueño no los levanta. Mismo formato. Bloquear rige al instante."
          },
          "unknown_destination": {
            "type": "string",
            "enum": [
              "ask",
              "block"
            ],
            "default": "ask",
            "description": "Qué hacer con un destino VÁLIDO que no está en ninguna lista. `ask` (por defecto): el pago queda `pending_approval` con `approval_reason: unknown_destination`, sin importar el monto. `block`: se rechaza con `destination_not_allowed`. Un destino inválido siempre se rechaza. El valor `allow` no existe en esta versión. Tope: 10 destinos nuevos por agente por día; el siguiente se rechaza con `unknown_destination_limit`."
          },
          "approval_over": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "destination_window_over": {
            "oneOf": [
              {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "const": "off"
                  }
                ],
                "description": "Anti-fraccionamiento por destino en 24 h: un monto, o \"off\" para apagarlo A PROPOSITO. null = vale lo mismo que `per_spend_limit`."
              },
              {
                "type": "null"
              }
            ]
          },
          "max_pending": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 5
          },
          "approval_ttl_minutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 60,
            "default": 15
          },
          "valid_until": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Después de esta fecha el agente no puede pagar (`permission_expired`)."
              },
              {
                "type": "null"
              }
            ]
          },
          "paused": {
            "type": "boolean"
          },
          "livemode": {
            "type": "boolean"
          },
          "effective_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "id",
          "agent_id",
          "version",
          "hash",
          "per_spend_limit",
          "daily_cap",
          "monthly_cap",
          "lifetime_cap",
          "allowed_destinations",
          "trusted_destinations",
          "blocked_destinations",
          "unknown_destination",
          "approval_over",
          "destination_window_over",
          "max_pending",
          "approval_ttl_minutes",
          "valid_until",
          "paused",
          "livemode",
          "effective_at",
          "created_at",
          "request_id"
        ],
        "description": "Reglas del agente. El agente las LEE; solo el dueño las escribe."
      },
      "PolicyInput": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "integer",
            "minimum": 1,
            "description": "Versión que el cliente leyo. Si no coincide: 409 `policy_version_conflict`."
          },
          "per_spend_limit": {
            "$ref": "#/components/schemas/Money"
          },
          "daily_cap": {
            "$ref": "#/components/schemas/Money"
          },
          "monthly_cap": {
            "$ref": "#/components/schemas/Money"
          },
          "lifetime_cap": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "allowed_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "ALIAS de `trusted_destinations` (el nombre de antes de R-177; mismo contenido). Hosts, comodines de UN nivel (`*.ejemplo.com`) o direcciones 0x. Si mandas las dos listas deben ser iguales (si no, 400 `invalid_request`). Con `unknown_destination: block`, vacía = no pasa nada. Prohibidos los comodines sobre sufijos públicos."
          },
          "trusted_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "Destinos de confianza: el agente les paga sin preguntar (dentro de los topes). Hosts, comodines de UN nivel (`*.ejemplo.com`) o direcciones 0x. Con `unknown_destination: ask` puede estar vacía. Confiar en un destino NUEVO afloja las reglas: espera 10 min en prueba y 24 h en real."
          },
          "blocked_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "Destinos bloqueados: se rechazan SIEMPRE (`destination_not_allowed`). Ganan sobre los de confianza y el sí del dueño no los levanta. Mismo formato. Bloquear rige al instante."
          },
          "unknown_destination": {
            "type": "string",
            "enum": [
              "ask",
              "block"
            ],
            "default": "ask",
            "description": "Qué hacer con un destino VÁLIDO que no está en ninguna lista. `ask` (por defecto): el pago queda `pending_approval` con `approval_reason: unknown_destination`, sin importar el monto. `block`: se rechaza con `destination_not_allowed`. Un destino inválido siempre se rechaza. El valor `allow` no existe en esta versión. Tope: 10 destinos nuevos por agente por día; el siguiente se rechaza con `unknown_destination_limit`."
          },
          "approval_over": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "destination_window_over": {
            "oneOf": [
              {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "const": "off"
                  }
                ],
                "description": "Anti-fraccionamiento por destino en 24 h: un monto, o \"off\" para apagarlo A PROPOSITO. null = vale lo mismo que `per_spend_limit`."
              },
              {
                "type": "null"
              }
            ]
          },
          "max_pending": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 5
          },
          "approval_ttl_minutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 60,
            "default": 15
          },
          "valid_until": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Después de esta fecha el agente no puede pagar (`permission_expired`)."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "expected_version",
          "per_spend_limit",
          "daily_cap",
          "monthly_cap"
        ],
        "additionalProperties": false,
        "description": "Reemplaza las reglas por una VERSIÓN NUEVA (las versiones no se editan). Apretar vale al instante; AFLOJAR (subir un tope, agregar un destino, quitar la aprobación) espera: 10 min en prueba, 24 h en real."
      },
      "PolicyInputWithoutVersion": {
        "type": "object",
        "properties": {
          "per_spend_limit": {
            "$ref": "#/components/schemas/Money"
          },
          "daily_cap": {
            "$ref": "#/components/schemas/Money"
          },
          "monthly_cap": {
            "$ref": "#/components/schemas/Money"
          },
          "lifetime_cap": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "allowed_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "ALIAS de `trusted_destinations` (el nombre de antes de R-177; mismo contenido). Hosts, comodines de UN nivel (`*.ejemplo.com`) o direcciones 0x. Si mandas las dos listas deben ser iguales (si no, 400 `invalid_request`). Con `unknown_destination: block`, vacía = no pasa nada. Prohibidos los comodines sobre sufijos públicos."
          },
          "trusted_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "Destinos de confianza: el agente les paga sin preguntar (dentro de los topes). Hosts, comodines de UN nivel (`*.ejemplo.com`) o direcciones 0x. Con `unknown_destination: ask` puede estar vacía. Confiar en un destino NUEVO afloja las reglas: espera 10 min en prueba y 24 h en real."
          },
          "blocked_destinations": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 253
            },
            "maxItems": 1000,
            "uniqueItems": true,
            "description": "Destinos bloqueados: se rechazan SIEMPRE (`destination_not_allowed`). Ganan sobre los de confianza y el sí del dueño no los levanta. Mismo formato. Bloquear rige al instante."
          },
          "unknown_destination": {
            "type": "string",
            "enum": [
              "ask",
              "block"
            ],
            "default": "ask",
            "description": "Qué hacer con un destino VÁLIDO que no está en ninguna lista. `ask` (por defecto): el pago queda `pending_approval` con `approval_reason: unknown_destination`, sin importar el monto. `block`: se rechaza con `destination_not_allowed`. Un destino inválido siempre se rechaza. El valor `allow` no existe en esta versión. Tope: 10 destinos nuevos por agente por día; el siguiente se rechaza con `unknown_destination_limit`."
          },
          "approval_over": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Money"
              },
              {
                "type": "null"
              }
            ]
          },
          "destination_window_over": {
            "oneOf": [
              {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/Money"
                  },
                  {
                    "const": "off"
                  }
                ],
                "description": "Anti-fraccionamiento por destino en 24 h: un monto, o \"off\" para apagarlo A PROPOSITO. null = vale lo mismo que `per_spend_limit`."
              },
              {
                "type": "null"
              }
            ]
          },
          "max_pending": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 5
          },
          "approval_ttl_minutes": {
            "type": "integer",
            "minimum": 5,
            "maximum": 60,
            "default": 15
          },
          "valid_until": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time",
                "description": "Después de esta fecha el agente no puede pagar (`permission_expired`)."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "per_spend_limit",
          "daily_cap",
          "monthly_cap"
        ],
        "additionalProperties": false
      },
      "PolicyChange": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PolicyChangeId"
          },
          "object": {
            "const": "policy_change"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "kind": {
            "type": "string",
            "enum": [
              "tightening",
              "loosening"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "applied",
              "pending",
              "cancelled"
            ]
          },
          "from_version": {
            "type": "integer",
            "minimum": 1
          },
          "to_version": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 2
              },
              {
                "type": "null"
              }
            ]
          },
          "loosened_fields": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            },
            "description": "Que campos aflojan (vacío si solo aprieta)."
          },
          "requested_at": {
            "type": "string",
            "format": "date-time"
          },
          "effective_at": {
            "type": "string",
            "format": "date-time"
          },
          "applied_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "cancelled_at": {
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "id",
          "object",
          "agent_id",
          "kind",
          "status",
          "from_version",
          "to_version",
          "loosened_fields",
          "requested_at",
          "effective_at",
          "applied_at",
          "cancelled_at",
          "request_id"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "applied"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "applied_at": {
                  "not": {
                    "type": "null"
                  }
                },
                "cancelled_at": {
                  "type": "null"
                }
              },
              "required": [
                "applied_at",
                "cancelled_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "cancelled"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "cancelled_at": {
                  "not": {
                    "type": "null"
                  }
                },
                "applied_at": {
                  "type": "null"
                }
              },
              "required": [
                "cancelled_at",
                "applied_at"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "pending"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "applied_at": {
                  "type": "null"
                },
                "cancelled_at": {
                  "type": "null"
                }
              },
              "required": [
                "applied_at",
                "cancelled_at"
              ]
            }
          }
        ],
        "description": "Un cambio de reglas. Si afloja, queda `pending` hasta `effective_at` y se puede cancelar (\"No fui yo\")."
      },
      "PolicyUpdateResult": {
        "type": "object",
        "properties": {
          "object": {
            "const": "policy_update"
          },
          "policy": {
            "$ref": "#/components/schemas/Policy"
          },
          "change": {
            "$ref": "#/components/schemas/PolicyChange"
          }
        },
        "required": [
          "object",
          "policy",
          "change"
        ],
        "description": "`policy` es la versión VIGENTE tras el cambio (la anterior si el cambio quedo pendiente)."
      },
      "Destination": {
        "type": "object",
        "properties": {
          "object": {
            "const": "destination"
          },
          "agent_id": {
            "$ref": "#/components/schemas/AgentId"
          },
          "destination": {
            "type": "string",
            "maxLength": 253
          },
          "kind": {
            "type": "string",
            "enum": [
              "domain",
              "wildcard",
              "address"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "pending"
            ]
          },
          "effective_at": {
            "type": "string",
            "format": "date-time"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "agent_id",
          "destination",
          "kind",
          "status",
          "effective_at",
          "request_id"
        ]
      },
      "Me": {
        "type": "object",
        "properties": {
          "object": {
            "const": "me"
          },
          "livemode": {
            "type": "boolean"
          },
          "api_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
          },
          "key": {
            "type": "object",
            "properties": {
              "id": {
                "$ref": "#/components/schemas/KeyId"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "agent",
                  "owner"
                ]
              },
              "prefix": {
                "type": "string"
              },
              "last4": {
                "type": "string",
                "pattern": "^[A-Za-z0-9]{4}$"
              },
              "scope": {
                "type": "string",
                "enum": [
                  "full",
                  "read_only"
                ]
              },
              "expires_at": {
                "oneOf": [
                  {
                    "type": "string",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "kind",
              "prefix",
              "last4",
              "scope",
              "expires_at"
            ]
          },
          "agent": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Agent"
              },
              {
                "type": "null"
              }
            ]
          },
          "policy_version": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "owner_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          },
          "message": {
            "type": "string",
            "maxLength": 300
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "livemode",
          "api_version",
          "key",
          "agent",
          "policy_version",
          "owner_id",
          "message",
          "request_id"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "key": {
                  "properties": {
                    "kind": {
                      "const": "owner"
                    }
                  },
                  "required": [
                    "kind"
                  ]
                }
              },
              "required": [
                "key"
              ]
            },
            "then": {
              "properties": {
                "agent": {
                  "type": "null"
                },
                "policy_version": {
                  "type": "null"
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "key": {
                  "properties": {
                    "kind": {
                      "const": "agent"
                    }
                  },
                  "required": [
                    "kind"
                  ]
                }
              },
              "required": [
                "key"
              ]
            },
            "then": {
              "properties": {
                "agent": {
                  "not": {
                    "type": "null"
                  }
                },
                "policy_version": {
                  "not": {
                    "type": "null"
                  }
                }
              }
            }
          }
        ],
        "description": "Quién soy: sirve para \"Probar la conexión\". Con llave de dueño `agent` es null."
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/EventId"
          },
          "object": {
            "const": "event"
          },
          "type": {
            "type": "string",
            "enum": [
              "spend.pending_approval",
              "spend.approved",
              "spend.declined",
              "spend.processing",
              "spend.settled",
              "spend.failed",
              "spend.expired",
              "spend.cancelled",
              "approval.requested",
              "approval.decided",
              "funding.awaiting_deposit",
              "funding.deposit_received",
              "funding.converted",
              "funding.failed",
              "wallet.low_balance",
              "agent.paused",
              "agent.resumed",
              "policy.updated",
              "webhook.test",
              "spend.refunded",
              "spend.disputed",
              "agent.created",
              "agent.archived",
              "api_key.created",
              "api_key.rotated",
              "api_key.revoked",
              "destination.added",
              "destination.removed",
              "policy.change_requested",
              "webhook_endpoint.created",
              "webhook_endpoint.paused",
              "notification_channel.added"
            ],
            "description": "Lista ABIERTA: pueden aparecer tipos nuevos sin cambiar la versión. Un tipo desconocido se ignora y la entrega se confirma con 2xx.",
            "x-open-enum": true
          },
          "api_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
            "description": "En webhooks, la versión fijada al crear el destino."
          },
          "created": {
            "type": "string",
            "format": "date-time"
          },
          "livemode": {
            "type": "boolean",
            "description": "false = práctica. Va en CADA evento (O-112)."
          },
          "sequence": {
            "type": "integer",
            "minimum": 1,
            "description": "Entero creciente por entorno: ordena y descarta un evento anterior a otro ya aplicado."
          },
          "agent_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AgentId"
              },
              {
                "type": "null"
              }
            ]
          },
          "data": {
            "type": "object",
            "properties": {
              "object": {
                "type": "object",
                "description": "El mismo objeto de la API; su forma depende de `type`."
              }
            },
            "required": [
              "object"
            ]
          },
          "request": {
            "type": "object",
            "properties": {
              "id": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/RequestId"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "idempotency_key": {
                "oneOf": [
                  {
                    "type": "string",
                    "maxLength": 128
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "id",
              "idempotency_key"
            ],
            "description": "La petición que lo causo, si hubo una."
          }
        },
        "required": [
          "id",
          "object",
          "type",
          "api_version",
          "created",
          "livemode",
          "sequence",
          "agent_id",
          "data",
          "request"
        ],
        "description": "Evento (webhook y `GET /v1/events`). Entrega al menos una vez: deduplica por `id`. Un evento por cambio de estado del pago.",
        "allOf": [
          {
            "if": {
              "properties": {
                "type": {
                  "pattern": "^spend\\."
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/Spend"
                    }
                  },
                  "required": [
                    "object"
                  ]
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "pattern": "^approval\\."
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/Approval"
                    }
                  },
                  "required": [
                    "object"
                  ]
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "pattern": "^agent\\."
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/Agent"
                    }
                  },
                  "required": [
                    "object"
                  ]
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "pattern": "^policy\\.updated$"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/Policy"
                    }
                  },
                  "required": [
                    "object"
                  ]
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "pattern": "^policy\\.change_requested$"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "properties": {
                    "object": {
                      "$ref": "#/components/schemas/PolicyChange"
                    }
                  },
                  "required": [
                    "object"
                  ]
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "type": {
                  "pattern": "^api_key\\."
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "properties": {
                    "object": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/ApiKey"
                        },
                        {
                          "not": {
                            "required": [
                              "secret"
                            ]
                          }
                        }
                      ]
                    }
                  },
                  "required": [
                    "object"
                  ]
                }
              }
            }
          }
        ]
      },
      "CreateAgentRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60
          },
          "policy": {
            "$ref": "#/components/schemas/PolicyInputWithoutVersion"
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false,
        "description": "Crea un agente. Sin `policy` nace con las reglas por defecto: lista de confianza VACÍA y `unknown_destination: ask` (cada destino nuevo pide el permiso del dueño; el agente no paga a nadie por su cuenta hasta que el dueño apruebe o confíe)."
      },
      "UpdateAgentRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "AddDestinationRequest": {
        "type": "object",
        "properties": {
          "destination": {
            "type": "string",
            "maxLength": 253
          },
          "expected_version": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "destination",
          "expected_version"
        ],
        "additionalProperties": false
      },
      "CreateKeyRequest": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "full",
              "read_only"
            ],
            "default": "full"
          },
          "expires_in_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "description": "Por defecto 90 en prueba y 30 en real. No existe \"sin vencimiento\"."
          },
          "api_version": {
            "type": "string",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
            "description": "Versión a fijar; por defecto la vigente."
          }
        },
        "required": [],
        "additionalProperties": false
      },
      "RotateKeyRequest": {
        "type": "object",
        "properties": {
          "grace_days": {
            "type": "integer",
            "minimum": 0,
            "maximum": 7,
            "default": 7,
            "description": "Convivencia de la llave vieja. 0 = revocarla ya."
          }
        },
        "required": [],
        "additionalProperties": false
      },
      "ClockAdvanceRequest": {
        "type": "object",
        "properties": {
          "seconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2592000,
            "description": "Hasta 30 días por llamada."
          }
        },
        "required": [
          "seconds"
        ],
        "additionalProperties": false
      },
      "FundTestRequest": {
        "type": "object",
        "properties": {
          "amount": {
            "$ref": "#/components/schemas/Money"
          }
        },
        "required": [
          "amount"
        ],
        "additionalProperties": false,
        "description": "Suma dinero de práctica a la bolsa. Tope de saldo de práctica: 10000.00; 5 recargas al día."
      },
      "TestClock": {
        "type": "object",
        "properties": {
          "object": {
            "const": "test_clock"
          },
          "now": {
            "type": "string",
            "format": "date-time"
          },
          "offset_seconds": {
            "type": "integer",
            "minimum": 0
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "now",
          "offset_seconds",
          "request_id"
        ],
        "description": "Reloj de práctica. Adelantarlo vence aprobaciones y reinicia topes diarios."
      },
      "TestReset": {
        "type": "object",
        "properties": {
          "object": {
            "const": "test_reset"
          },
          "archived_agents": {
            "type": "integer",
            "minimum": 0
          },
          "balance": {
            "$ref": "#/components/schemas/Money"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "archived_agents",
          "balance",
          "request_id"
        ],
        "description": "Reinicia el entorno de práctica (archivar y crear de nuevo; no purga el libro)."
      },
      "TestFunding": {
        "type": "object",
        "properties": {
          "object": {
            "const": "test_funding"
          },
          "amount": {
            "$ref": "#/components/schemas/Money"
          },
          "balance_after": {
            "$ref": "#/components/schemas/Money"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "amount",
          "balance_after",
          "request_id"
        ]
      },
      "TestRedelivery": {
        "type": "object",
        "properties": {
          "object": {
            "const": "test_redelivery"
          },
          "event_id": {
            "$ref": "#/components/schemas/EventId"
          },
          "endpoints_queued": {
            "type": "integer",
            "minimum": 0
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        },
        "required": [
          "object",
          "event_id",
          "endpoints_queued",
          "request_id"
        ]
      }
    },
    "parameters": {
      "NouronVersion": {
        "name": "Nouron-Version",
        "in": "header",
        "required": false,
        "description": "Versión de la API (fecha). Si falta, se usa la versión fijada a tu llave. Una versión desconocida es 400 `unsupported_version`.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
          "examples": [
            "2026-10-01"
          ]
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "OBLIGATORIA. 16 a 128 caracteres [A-Za-z0-9_-] (un UUID v4 sirve). Una llave NUEVA por cada pago distinto; la MISMA solo para repetir el mismo intento. Un pago `failed` necesita una llave nueva.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{16,128}$"
        }
      },
      "OptionalIdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Opcional en acciones del dueño; si se manda, la repeticion devuelve el mismo resultado sin duplicar (alcance: dueño y entorno).",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{16,128}$"
        }
      },
      "SpendIdPath": {
        "name": "spend_id",
        "in": "path",
        "required": true,
        "description": "Id del pago.",
        "schema": {
          "$ref": "#/components/schemas/SpendId"
        }
      },
      "ApprovalIdPath": {
        "name": "approval_id",
        "in": "path",
        "required": true,
        "description": "Id de la aprobación.",
        "schema": {
          "$ref": "#/components/schemas/ApprovalId"
        }
      },
      "ReceiptIdPath": {
        "name": "receipt_id",
        "in": "path",
        "required": true,
        "description": "Id del recibo.",
        "schema": {
          "$ref": "#/components/schemas/ReceiptId"
        }
      },
      "AgentIdPath": {
        "name": "agent_id",
        "in": "path",
        "required": true,
        "description": "Id del agente.",
        "schema": {
          "$ref": "#/components/schemas/AgentId"
        }
      },
      "KeyIdPath": {
        "name": "key_id",
        "in": "path",
        "required": true,
        "description": "Id de la llave (no la llave).",
        "schema": {
          "$ref": "#/components/schemas/KeyId"
        }
      },
      "PolicyChangeIdPath": {
        "name": "change_id",
        "in": "path",
        "required": true,
        "description": "Id del cambio de reglas.",
        "schema": {
          "$ref": "#/components/schemas/PolicyChangeId"
        }
      },
      "EventIdPath": {
        "name": "event_id",
        "in": "path",
        "required": true,
        "description": "Id del evento.",
        "schema": {
          "$ref": "#/components/schemas/EventId"
        }
      },
      "DestinationPath": {
        "name": "destination",
        "in": "path",
        "required": true,
        "description": "Destino permitido, codificado en URL (el comodín `*.x.com` va como `%2A.x.com`).",
        "schema": {
          "type": "string",
          "maxLength": 253
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Elementos por página, de 1 a 50 (10 por defecto).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 50,
          "default": 10
        }
      },
      "StartingAfter": {
        "name": "starting_after",
        "in": "query",
        "required": false,
        "description": "Id del último elemento de la página anterior. Excluyente con `ending_before`.",
        "schema": {
          "type": "string",
          "maxLength": 64
        }
      },
      "EndingBefore": {
        "name": "ending_before",
        "in": "query",
        "required": false,
        "description": "Id del primer elemento de la página siguiente. Excluyente con `starting_after`.",
        "schema": {
          "type": "string",
          "maxLength": 64
        }
      },
      "SpendStatusFilter": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "Filtra por estado.",
        "schema": {
          "type": "string",
          "enum": [
            "pending_approval",
            "approved",
            "processing",
            "settled",
            "declined",
            "failed",
            "expired",
            "cancelled",
            "refunded",
            "disputed"
          ]
        }
      },
      "DestinationFilter": {
        "name": "destination",
        "in": "query",
        "required": false,
        "description": "Filtra por destino exacto (normalizado).",
        "schema": {
          "type": "string",
          "maxLength": 253
        }
      },
      "AgentIdFilter": {
        "name": "agent_id",
        "in": "query",
        "required": false,
        "description": "Solo con llave de dueño: limita a un agente. Con llave de agente se ignora (siempre es el propio).",
        "schema": {
          "$ref": "#/components/schemas/AgentId"
        }
      },
      "CreatedFilter": {
        "name": "created",
        "in": "query",
        "required": false,
        "description": "Rango de fechas: `created[gte]` y `created[lte]` (ISO 8601 con zona).",
        "schema": {
          "type": "object",
          "properties": {
            "gte": {
              "type": "string",
              "format": "date-time"
            },
            "lte": {
              "type": "string",
              "format": "date-time"
            }
          },
          "additionalProperties": false
        },
        "style": "deepObject",
        "explode": true
      },
      "EventTypeFilter": {
        "name": "type",
        "in": "query",
        "required": false,
        "description": "Filtra por tipo de evento.",
        "schema": {
          "type": "string",
          "enum": [
            "spend.pending_approval",
            "spend.approved",
            "spend.declined",
            "spend.processing",
            "spend.settled",
            "spend.failed",
            "spend.expired",
            "spend.cancelled",
            "approval.requested",
            "approval.decided",
            "funding.awaiting_deposit",
            "funding.deposit_received",
            "funding.converted",
            "funding.failed",
            "wallet.low_balance",
            "agent.paused",
            "agent.resumed",
            "policy.updated",
            "webhook.test",
            "spend.refunded",
            "spend.disputed",
            "agent.created",
            "agent.archived",
            "api_key.created",
            "api_key.rotated",
            "api_key.revoked",
            "destination.added",
            "destination.removed",
            "policy.change_requested",
            "webhook_endpoint.created",
            "webhook_endpoint.paused",
            "notification_channel.added"
          ],
          "x-open-enum": true
        }
      },
      "WaitSeconds": {
        "name": "wait_seconds",
        "in": "query",
        "required": false,
        "description": "Espera larga: la respuesta se retiene hasta 20 s o hasta que el estado cambie (lo que ocurra antes). Evita 30 consultas seguidas.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "maximum": 20,
          "default": 0
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "Identificador de la petición. Esta en TODAS las respuestas, de exito o de error. Dalo a soporte.",
        "schema": {
          "$ref": "#/components/schemas/RequestId"
        }
      },
      "NouronVersion": {
        "description": "La versión de la API realmente usada.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitLimit": {
        "description": "Peticiones permitidas en la ventana.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Peticiones que quedan en la ventana.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Segundos hasta que se reinicia la ventana.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Segundos que debes esperar antes de reintentar.",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "WwwAuthenticate": {
        "description": "Esquema de autenticación esperado (`Bearer`). En el hito F2 (OAuth 2.1) se le agregara `resource_metadata`.",
        "schema": {
          "type": "string",
          "examples": [
            "Bearer realm=\"nouron-pass\""
          ]
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "400. La petición esta mal escrita. NUNCA crea un pago ni retiene cupo.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "invalid_amount_format": {
                "value": {
                  "ok": false,
                  "status": 400,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "invalid_request_error",
                    "code": "invalid_amount_format",
                    "message": "«abc» no es un monto válido. Usa un número positivo como texto con hasta 6 decimales, por ejemplo \"4.80\".",
                    "param": "amount",
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "413. El cuerpo supera 16 KiB.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "payload_too_large": {
                "value": {
                  "ok": false,
                  "status": 413,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "invalid_request_error",
                    "code": "payload_too_large",
                    "message": "El cuerpo supera el máximo de 16 KiB.",
                    "param": null,
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "401. No sabemos quién llama. El mensaje dice QUÉ HACER y NUNCA repite la llave recibida.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "WWW-Authenticate": {
            "$ref": "#/components/headers/WwwAuthenticate"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "invalid_api_key": {
                "value": {
                  "ok": false,
                  "status": 401,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "authentication_error",
                    "code": "invalid_api_key",
                    "message": "La llave no es válida: revisa que esté completa, sin espacios ni saltos de línea, y que empiece por np_test_ o np_live_.",
                    "param": null,
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "403. La llave es válida pero no puede hacer esto (tipo de llave, solo lectura, otro entorno).",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "wrong_key_type": {
                "value": {
                  "ok": false,
                  "status": 403,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "permission_error",
                    "code": "wrong_key_type",
                    "message": "Esta operación exige una llave de dueño. Las llaves de dueño nunca se pegan en un agente.",
                    "param": null,
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "404. No existe en este entorno. Con una llave real, las rutas /v1/test/* tampoco existen.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "not_found": {
                "value": {
                  "ok": false,
                  "status": 404,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "invalid_request_error",
                    "code": "not_found",
                    "message": "No existe el pago spd_… en este entorno.",
                    "param": "spend_id",
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "Conflict": {
        "description": "409. Choca con el estado actual (idempotencia, cancelar tarde, versión de reglas).",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "idempotency_conflict": {
                "value": {
                  "ok": false,
                  "status": 409,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "idempotency_error",
                    "code": "idempotency_conflict",
                    "message": "Reusaste la llave de idempotencia con otra petición: cambió el destino. Usa una llave nueva para un pago distinto.",
                    "param": "destination",
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "Unprocessable": {
        "description": "422. Bien escrita, pero una regla del producto no la acepta (límites, comodines prohibidos).",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "destination_wildcard_not_allowed": {
                "value": {
                  "ok": false,
                  "status": 422,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "invalid_request_error",
                    "code": "destination_wildcard_not_allowed",
                    "message": "No se permiten comodines sobre sufijos públicos como *.vercel.app.",
                    "param": "destination",
                    "retry": "after_fixing",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "429. Demasiado rápido. Reintenta pasado `Retry-After`, con retroceso exponencial y algo de azar.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "rate_limited": {
                "value": {
                  "ok": false,
                  "status": 429,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "rate_limit_error",
                    "code": "rate_limited",
                    "message": "Tu agente llamó 20 veces en un minuto. Pass lo frenó. Revisa si está en un bucle.",
                    "param": null,
                    "retry": "as_is",
                    "retry_after_ms": 1000,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "500. Fallo nuestro. Reintenta con la MISMA llave de idempotencia: no paga dos veces.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "internal_error": {
                "value": {
                  "ok": false,
                  "status": 500,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "api_error",
                    "code": "internal_error",
                    "message": "Algo falló de nuestro lado. Reintenta con la misma llave de idempotencia.",
                    "param": null,
                    "retry": "as_is",
                    "retry_after_ms": null,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "503. No disponible un momento (o plataforma pausada por seguridad).",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "service_unavailable": {
                "value": {
                  "ok": false,
                  "status": 503,
                  "request_id": "req_3z6y1wUd",
                  "error": {
                    "type": "api_error",
                    "code": "service_unavailable",
                    "message": "Servicio no disponible por un momento.",
                    "param": null,
                    "retry": "as_is",
                    "retry_after_ms": 1000,
                    "outcome_unknown": false
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "x-nouron": {
    "api_version": "2026-10-01",
    "supported_versions": [
      "2026-10-01"
    ],
    "version_header": "Nouron-Version",
    "decision_note": "D8: un rechazo por regla NO es un error HTTP. Se responde 2xx con `status: declined` y un motivo estable; una entrada inválida es 400 y no crea pago.",
    "keys": {
      "environments": [
        "test",
        "live"
      ],
      "kinds": [
        "agent",
        "owner"
      ],
      "format": "np_<entorno>_<tipo>_<32 alfanumericos><6 de verificación CRC-32 en base 62>",
      "scanner_regex": "(?<![A-Za-z0-9])np_(?:test|live)_(?:agent|owner)_[A-Za-z0-9]{38}(?![A-Za-z0-9])"
    },
    "statuses": [
      "pending_approval",
      "approved",
      "processing",
      "settled",
      "declined",
      "failed",
      "expired",
      "cancelled",
      "refunded",
      "disputed"
    ],
    "terminal_statuses": [
      "settled",
      "declined",
      "failed",
      "expired",
      "cancelled",
      "refunded"
    ],
    "holding_statuses": [
      "pending_approval",
      "approved",
      "processing"
    ],
    "transitions": [
      {
        "id": "T1",
        "from": "creation",
        "to": "declined",
        "gate": "create",
        "actor": "agent",
        "events": [
          "spend.declined"
        ],
        "phase": "A"
      },
      {
        "id": "T2",
        "from": "creation",
        "to": "pending_approval",
        "gate": "create",
        "actor": "agent",
        "events": [
          "spend.pending_approval",
          "approval.requested"
        ],
        "phase": "A"
      },
      {
        "id": "T3",
        "from": "creation",
        "to": "approved",
        "gate": "create",
        "actor": "agent",
        "events": [
          "spend.approved"
        ],
        "phase": "A"
      },
      {
        "id": "T4",
        "from": "pending_approval",
        "to": "approved",
        "gate": "approval",
        "actor": "owner",
        "events": [
          "approval.decided",
          "spend.approved"
        ],
        "phase": "A"
      },
      {
        "id": "T5",
        "from": "pending_approval",
        "to": "declined",
        "gate": null,
        "actor": "owner",
        "events": [
          "approval.decided",
          "spend.declined"
        ],
        "phase": "A"
      },
      {
        "id": "T6",
        "from": "pending_approval",
        "to": "declined",
        "gate": "approval",
        "actor": "system",
        "events": [
          "approval.decided",
          "spend.declined"
        ],
        "phase": "A"
      },
      {
        "id": "T7",
        "from": "pending_approval",
        "to": "expired",
        "gate": null,
        "actor": "clock",
        "events": [
          "spend.expired"
        ],
        "phase": "A"
      },
      {
        "id": "T8",
        "from": "pending_approval",
        "to": "cancelled",
        "gate": null,
        "actor": "agent",
        "events": [
          "spend.cancelled"
        ],
        "phase": "A"
      },
      {
        "id": "T9",
        "from": "approved",
        "to": "processing",
        "gate": "execute",
        "actor": "system",
        "events": [
          "spend.processing"
        ],
        "phase": "A"
      },
      {
        "id": "T10",
        "from": "approved",
        "to": "pending_approval",
        "gate": "execute",
        "actor": "system",
        "events": [
          "spend.pending_approval",
          "approval.requested"
        ],
        "phase": "A"
      },
      {
        "id": "T11",
        "from": "approved",
        "to": "declined",
        "gate": "execute",
        "actor": "system",
        "events": [
          "spend.declined"
        ],
        "phase": "A"
      },
      {
        "id": "T12",
        "from": "approved",
        "to": "expired",
        "gate": "execute",
        "actor": "clock",
        "events": [
          "spend.expired"
        ],
        "phase": "A"
      },
      {
        "id": "T13",
        "from": "approved",
        "to": "cancelled",
        "gate": null,
        "actor": "agent",
        "events": [
          "spend.cancelled"
        ],
        "phase": "A"
      },
      {
        "id": "T14",
        "from": "processing",
        "to": "settled",
        "gate": null,
        "actor": "system",
        "events": [
          "spend.settled"
        ],
        "phase": "A"
      },
      {
        "id": "T15",
        "from": "processing",
        "to": "failed",
        "gate": null,
        "actor": "system",
        "events": [
          "spend.failed"
        ],
        "phase": "A"
      },
      {
        "id": "T17",
        "from": "settled",
        "to": "refunded",
        "gate": null,
        "actor": "system",
        "events": [
          "spend.refunded"
        ],
        "phase": "D"
      },
      {
        "id": "T18",
        "from": "settled",
        "to": "disputed",
        "gate": null,
        "actor": "owner",
        "events": [
          "spend.disputed"
        ],
        "phase": "D"
      }
    ],
    "reasons": {
      "decline": [
        "agent_paused",
        "destination_not_allowed",
        "insufficient_balance",
        "per_spend_limit",
        "daily_cap",
        "monthly_cap",
        "lifetime_cap",
        "rolling_24h_cap",
        "permission_expired",
        "too_many_pending",
        "owner_declined",
        "price_above_max",
        "quote_mismatch",
        "rules_unavailable",
        "approval_incomplete",
        "approval_invalid",
        "unknown_destination_limit"
      ],
      "approval": [
        "approval_over",
        "destination_window",
        "history_incomplete",
        "dual_approval",
        "possible_duplicate",
        "new_destination",
        "outside_hours",
        "max_per_destination_24h",
        "approval_changed",
        "payto_changed",
        "unknown_destination",
        "sandbox_magic_amount"
      ],
      "failure": [
        "rail_error",
        "vendor_error",
        "delivery_failed"
      ],
      "processing_detail": [
        "awaiting_settlement",
        "outcome_unknown"
      ],
      "declined_at_gate": [
        "create",
        "approval",
        "execute"
      ],
      "pause_detail": [
        "paused",
        "owner_emergency_pause",
        "platform_emergency_pause",
        "status_unreadable",
        "key_revoked"
      ],
      "next_action": [
        "none",
        "wait_for_owner",
        "check_status_later",
        "ask_owner_to_add_destination",
        "ask_owner_to_raise_limit",
        "ask_owner_to_review",
        "retry_later",
        "retry_same_idempotency_key",
        "new_attempt_needs_new_key",
        "do_not_retry",
        "fix_request",
        "contact_support",
        "use_other_key_type",
        "verify_key",
        "complete_verification",
        "not_available_in_country"
      ]
    },
    "errors": [
      {
        "code": "invalid_json",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "El cuerpo no es JSON válido."
      },
      {
        "code": "invalid_request",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "La petición tiene un valor inválido; `param` dice cual."
      },
      {
        "code": "missing_parameter",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Falta un campo obligatorio; `param` dice cual."
      },
      {
        "code": "unknown_parameter",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Se envio un campo que la API no conoce (los esquemas no admiten campos extra)."
      },
      {
        "code": "invalid_amount_format",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "El monto no es un texto decimal válido (hasta 12 enteros y 6 decimales, sin signo ni notacion cientifica)."
      },
      {
        "code": "amount_not_positive",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "El monto debe ser mayor que cero."
      },
      {
        "code": "unsupported_currency",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "La moneda no esta soportada (en esta fase solo `usdc`)."
      },
      {
        "code": "invalid_destination",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "El destino no es un dominio, comodín ni dirección 0x válidos."
      },
      {
        "code": "resource_required",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Un destino que es un dominio exige `resource` (la URL exacta que se quiere comprar)."
      },
      {
        "code": "resource_not_allowed_for_address",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Un destino que es una dirección 0x es una transferencia: no lleva `resource`."
      },
      {
        "code": "invalid_resource",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "`resource` debe ser https, sin credenciales, sin puerto extrano, de hasta 2048 caracteres y con cuerpo solo en POST."
      },
      {
        "code": "resource_host_mismatch",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "La URL de `resource` debe estar en el mismo dominio que `destination`."
      },
      {
        "code": "invalid_memo",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "`memo` debe ser texto de hasta 280 caracteres."
      },
      {
        "code": "invalid_client_reference",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "`client_reference` debe ser texto de hasta 64 caracteres."
      },
      {
        "code": "missing_idempotency_key",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Falta la cabecera `Idempotency-Key`: es obligatoria para crear un pago."
      },
      {
        "code": "invalid_idempotency_key",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "La llave de idempotencia debe tener de 16 a 128 caracteres [A-Za-z0-9_-] (un UUID sirve) y no ser un valor de juguete."
      },
      {
        "code": "invalid_pagination",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "`limit` (1-50), `starting_after` o `ending_before` inválidos."
      },
      {
        "code": "invalid_filter",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Un filtro de la lista tiene un valor inválido."
      },
      {
        "code": "unsupported_version",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "La versión de `Nouron-Version` no existe. Quita la cabecera para usar la fijada a tu llave."
      },
      {
        "code": "invalid_policy",
        "type": "invalid_request_error",
        "http": 400,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Las reglas enviadas tienen un valor mal formado; `param` dice cual."
      },
      {
        "code": "payload_too_large",
        "type": "invalid_request_error",
        "http": 413,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "El cuerpo supera el máximo (16 KiB)."
      },
      {
        "code": "missing_api_key",
        "type": "authentication_error",
        "http": 401,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "verify_key",
        "summary": "Falta la cabecera `Authorization: Bearer <api_key>`."
      },
      {
        "code": "invalid_api_key",
        "type": "authentication_error",
        "http": 401,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "verify_key",
        "summary": "La llave no es válida: revisa que este completa, sin espacios ni saltos de línea, y que empiece por np_test_ o np_live_."
      },
      {
        "code": "api_key_revoked",
        "type": "authentication_error",
        "http": 401,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "verify_key",
        "summary": "La llave fue revocada. Pide una nueva al dueño en Llaves de API."
      },
      {
        "code": "api_key_expired",
        "type": "authentication_error",
        "http": 401,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "verify_key",
        "summary": "La llave venció. Rota la llave en Llaves de API."
      },
      {
        "code": "permission_denied",
        "type": "permission_error",
        "http": 403,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "ask_owner_to_review",
        "summary": "La llave no tiene permiso para esta operación."
      },
      {
        "code": "wrong_key_type",
        "type": "permission_error",
        "http": 403,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "use_other_key_type",
        "summary": "Esta operación exige otro tipo de llave (agente u dueño). La llave de dueño nunca se pega en un agente."
      },
      {
        "code": "read_only_key",
        "type": "permission_error",
        "http": 403,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "use_other_key_type",
        "summary": "La llave es de solo lectura y esta operación escribe."
      },
      {
        "code": "wrong_environment",
        "type": "permission_error",
        "http": 403,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "verify_key",
        "summary": "El recurso o la operación pertenece al otro entorno (prueba o real)."
      },
      {
        "code": "not_found",
        "type": "invalid_request_error",
        "http": 404,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "No existe ese recurso en este entorno. Con una llave real, las rutas de simulación (/v1/test/*) tampoco existen."
      },
      {
        "code": "idempotency_conflict",
        "type": "idempotency_error",
        "http": 409,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "new_attempt_needs_new_key",
        "summary": "Reusaste una llave de idempotencia con una petición distinta; `changed_fields` dice que cambio."
      },
      {
        "code": "idempotency_key_in_use",
        "type": "idempotency_error",
        "http": 409,
        "retryable": true,
        "retry_after_header": true,
        "next_action": "retry_same_idempotency_key",
        "summary": "Otra petición con la misma llave sigue en curso. Reintenta igual pasado `Retry-After`."
      },
      {
        "code": "cancel_too_late",
        "type": "invalid_request_error",
        "http": 409,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "check_status_later",
        "summary": "El pago ya fue enviado (`processing`) o liquidado: no se puede cancelar."
      },
      {
        "code": "spend_not_cancellable",
        "type": "invalid_request_error",
        "http": 409,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "none",
        "summary": "El pago ya termino (declined, failed, expired): no hay nada que cancelar."
      },
      {
        "code": "policy_version_conflict",
        "type": "invalid_request_error",
        "http": 409,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Las reglas cambiaron desde que las leiste (`expected_version` no coincide). Vuelve a leerlas."
      },
      {
        "code": "agent_name_taken",
        "type": "invalid_request_error",
        "http": 409,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Ya existe un agente activo con ese nombre."
      },
      {
        "code": "agent_not_archivable",
        "type": "invalid_request_error",
        "http": 409,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "check_status_later",
        "summary": "El agente tiene pagos retenidos o en curso: espera a que se liquiden, venzan o cancelen."
      },
      {
        "code": "agent_limit_reached",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "ask_owner_to_review",
        "summary": "Se alcanzo el máximo de agentes activos (5 en prueba, 10 en real)."
      },
      {
        "code": "key_limit_reached",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "ask_owner_to_review",
        "summary": "Un agente admite como máximo 3 llaves activas. Revoca una o rotala."
      },
      {
        "code": "quota_exceeded",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "ask_owner_to_review",
        "summary": "Se alcanzo un tope de uso del entorno de prueba (pagos por dueño, agentes archivados...). Reinicia el entorno o pide una revision."
      },
      {
        "code": "destination_wildcard_not_allowed",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "No se permiten comodines sobre sufijos públicos compartidos (*.vercel.app, *.github.io...) porque autorizan a terceros."
      },
      {
        "code": "destination_blocked",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "El destino esta en la lista global de bloqueo de Nouron y no se puede permitir."
      },
      {
        "code": "policy_inconsistent",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "fix_request",
        "summary": "Las reglas se contradicen (por ejemplo el tope por pago supera el diario)."
      },
      {
        "code": "agent_archived",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "ask_owner_to_review",
        "summary": "El agente esta archivado y no admite esta operación."
      },
      {
        "code": "capability_unavailable",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "not_available_in_country",
        "summary": "La función no está disponible para el país o el tipo de titular, o todavía no existe."
      },
      {
        "code": "verification_required",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "complete_verification",
        "summary": "La operación pide un nivel de verificación que el titular aún no tiene; el dueño lo completa en la consola."
      },
      {
        "code": "account_on_hold",
        "type": "invalid_request_error",
        "http": 422,
        "retryable": false,
        "retry_after_header": false,
        "next_action": "contact_support",
        "summary": "No se puede completar la operación ahora; escribe a soporte con el `Request-Id`. Mismo texto, forma y tiempo sea cual sea la causa."
      },
      {
        "code": "rate_limited",
        "type": "rate_limit_error",
        "http": 429,
        "retryable": true,
        "retry_after_header": true,
        "next_action": "retry_later",
        "summary": "Demasiadas peticiones. Espera `Retry-After` y reintenta con retroceso exponencial y algo de azar."
      },
      {
        "code": "agent_busy",
        "type": "rate_limit_error",
        "http": 429,
        "retryable": true,
        "retry_after_header": true,
        "next_action": "retry_same_idempotency_key",
        "summary": "Este agente ya tiene un pago en proceso de decision; reintenta igual pasado `Retry-After`."
      },
      {
        "code": "internal_error",
        "type": "api_error",
        "http": 500,
        "retryable": true,
        "retry_after_header": false,
        "next_action": "retry_same_idempotency_key",
        "summary": "Fallo nuestro. Reintenta con la misma llave de idempotencia; si persiste, escribe a soporte con el `Request-Id`."
      },
      {
        "code": "service_unavailable",
        "type": "api_error",
        "http": 503,
        "retryable": true,
        "retry_after_header": true,
        "next_action": "retry_same_idempotency_key",
        "summary": "Servicio no disponible por un momento. Reintenta con la misma llave pasado `Retry-After`."
      },
      {
        "code": "platform_paused",
        "type": "api_error",
        "http": 503,
        "retryable": true,
        "retry_after_header": true,
        "next_action": "contact_support",
        "summary": "Nouron pauso la plataforma por seguridad. Los pagos se rechazan hasta que se reanude."
      },
      {
        "code": "partner_unavailable",
        "type": "api_error",
        "http": 503,
        "retryable": true,
        "retry_after_header": true,
        "next_action": "retry_later",
        "summary": "Un servicio externo (socio) no responde. Reintenta pasado `Retry-After`."
      }
    ],
    "error_type_statuses": {
      "invalid_request_error": [
        400,
        404,
        409,
        413,
        422
      ],
      "authentication_error": [
        401
      ],
      "permission_error": [
        403
      ],
      "rate_limit_error": [
        429
      ],
      "idempotency_error": [
        409
      ],
      "api_error": [
        500,
        503
      ]
    },
    "events": [
      {
        "type": "spend.pending_approval",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "El pago espera la aprobación del dueño (T2, T10)."
      },
      {
        "type": "spend.approved",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "Pasaron las reglas; cupo reservado, aún no enviado (T3, T4)."
      },
      {
        "type": "spend.declined",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "No se pagó: una regla, el dueño o un cambio entre pasos (T1, T5, T6, T11)."
      },
      {
        "type": "spend.processing",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "Se envió al riel; sin resultado todavía (T9)."
      },
      {
        "type": "spend.settled",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "Pago confirmado; el objeto trae `settlement.receipt_id` (T14)."
      },
      {
        "type": "spend.failed",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "Se aprobó y el riel rechazó; no se movió dinero (T15)."
      },
      {
        "type": "spend.expired",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "La aprobación venció sin respuesta (T7, T12)."
      },
      {
        "type": "spend.cancelled",
        "group": "pagos",
        "phase": "fase1",
        "object": "spend",
        "audience": "agent",
        "description": "El agente canceló antes del envío (T8, T13)."
      },
      {
        "type": "approval.requested",
        "group": "aprobaciones",
        "phase": "fase1",
        "object": "approval",
        "audience": "owner",
        "description": "Se creó una aprobación pendiente para el dueño."
      },
      {
        "type": "approval.decided",
        "group": "aprobaciones",
        "phase": "fase1",
        "object": "approval",
        "audience": "owner",
        "description": "El dueño aprobó o rechazó; trae canal y referencia del aprobador."
      },
      {
        "type": "funding.awaiting_deposit",
        "group": "fondeo",
        "phase": "fase1",
        "object": "funding",
        "audience": "owner",
        "description": "Esperando un depósito en la bolsa de práctica."
      },
      {
        "type": "funding.deposit_received",
        "group": "fondeo",
        "phase": "fase1",
        "object": "funding",
        "audience": "owner",
        "description": "Llegó un depósito."
      },
      {
        "type": "funding.converted",
        "group": "fondeo",
        "phase": "fase1",
        "object": "funding",
        "audience": "owner",
        "description": "Un depósito se convirtió a dólares digitales de práctica."
      },
      {
        "type": "funding.failed",
        "group": "fondeo",
        "phase": "fase1",
        "object": "funding",
        "audience": "owner",
        "description": "Un depósito no se pudo completar."
      },
      {
        "type": "wallet.low_balance",
        "group": "billetera",
        "phase": "fase1",
        "object": "wallet",
        "audience": "owner",
        "description": "El saldo bajó del umbral de aviso."
      },
      {
        "type": "agent.paused",
        "group": "agentes",
        "phase": "fase1",
        "object": "agent",
        "audience": "agent",
        "description": "Un agente se pausó (el dueño, la pausa de emergencia o la plataforma)."
      },
      {
        "type": "agent.resumed",
        "group": "agentes",
        "phase": "fase1",
        "object": "agent",
        "audience": "agent",
        "description": "Un agente se reactivó."
      },
      {
        "type": "policy.updated",
        "group": "reglas",
        "phase": "fase1",
        "object": "policy",
        "audience": "agent",
        "description": "Se público una versión nueva de las reglas; trae `version` y `hash`."
      },
      {
        "type": "webhook.test",
        "group": "sistema",
        "phase": "fase1",
        "object": "webhook_test",
        "audience": "owner",
        "description": "Evento de prueba enviado a pedido del dueño; no hace falta suscribirse."
      },
      {
        "type": "spend.refunded",
        "group": "pagos",
        "phase": "fase2",
        "object": "spend",
        "audience": "agent",
        "description": "Devolución posterior a `settled` (T17)."
      },
      {
        "type": "spend.disputed",
        "group": "pagos",
        "phase": "fase2",
        "object": "spend",
        "audience": "agent",
        "description": "Reclamo abierto sobre un pago liquidado (T18)."
      },
      {
        "type": "agent.created",
        "group": "agentes",
        "phase": "auditoria",
        "object": "agent",
        "audience": "owner",
        "description": "Se creó un agente."
      },
      {
        "type": "agent.archived",
        "group": "agentes",
        "phase": "auditoria",
        "object": "agent",
        "audience": "owner",
        "description": "Se archivó un agente (sus llaves se revocan)."
      },
      {
        "type": "api_key.created",
        "group": "llaves",
        "phase": "auditoria",
        "object": "api_key",
        "audience": "owner",
        "description": "Se creó una llave de API (nunca incluye el secreto)."
      },
      {
        "type": "api_key.rotated",
        "group": "llaves",
        "phase": "auditoria",
        "object": "api_key",
        "audience": "owner",
        "description": "Se rotó una llave; la vieja convive hasta `grace_period_ends_at`."
      },
      {
        "type": "api_key.revoked",
        "group": "llaves",
        "phase": "auditoria",
        "object": "api_key",
        "audience": "owner",
        "description": "Se revocó una llave."
      },
      {
        "type": "destination.added",
        "group": "destinos",
        "phase": "auditoria",
        "object": "destination",
        "audience": "owner",
        "description": "Se agregó un destino permitido (puede tener espera antes de valer)."
      },
      {
        "type": "destination.removed",
        "group": "destinos",
        "phase": "auditoria",
        "object": "destination",
        "audience": "owner",
        "description": "Se quitó un destino permitido."
      },
      {
        "type": "policy.change_requested",
        "group": "reglas",
        "phase": "auditoria",
        "object": "policy_change",
        "audience": "owner",
        "description": "Se pidió un cambio que AFLOJA reglas; vale desde `effective_at` salvo que se cancele."
      },
      {
        "type": "webhook_endpoint.created",
        "group": "avisos",
        "phase": "auditoria",
        "object": "webhook_endpoint",
        "audience": "owner",
        "description": "Se creó un destino de webhook."
      },
      {
        "type": "webhook_endpoint.paused",
        "group": "avisos",
        "phase": "auditoria",
        "object": "webhook_endpoint",
        "audience": "owner",
        "description": "Un destino de webhook se pausó por fallos repetidos."
      },
      {
        "type": "notification_channel.added",
        "group": "avisos",
        "phase": "auditoria",
        "object": "notification_channel",
        "audience": "owner",
        "description": "Se agregó un canal de avisos (correo, Telegram...)."
      }
    ],
    "removed_v0_events": [
      "spend.created",
      "approval.expired"
    ],
    "open_enums": {
      "error_code": {
        "count": 53,
        "schema_pointer": "#/components/schemas/ErrorObject/properties/code",
        "shape": "^[a-z][a-z0-9_]{2,63}$",
        "description": "Código de error estable. Un código nuevo se trata por su estado HTTP y por `retry`."
      },
      "error_type": {
        "count": 6,
        "schema_pointer": "#/components/schemas/ErrorObject/properties/type",
        "shape": "^[a-z][a-z0-9_]{2,63}$",
        "description": "Familia del error. Un tipo nuevo se trata por su estado HTTP."
      },
      "event_type": {
        "count": 32,
        "schema_pointer": "#/components/schemas/Event/properties/type",
        "shape": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
        "description": "Tipo de evento (`recurso.accion`). Un evento desconocido se ignora y la entrega se confirma con 2xx."
      },
      "next_action_code": {
        "count": 16,
        "schema_pointer": "#/components/schemas/NextAction/properties/code",
        "shape": "^[a-z][a-z0-9_]{2,63}$",
        "description": "Qué hacer ahora. Un código desconocido se trata como `contact_support` si no hay otra pista."
      },
      "audit_action": {
        "count": null,
        "schema_pointer": null,
        "shape": "^[a-z_]{2,30}\\.[a-z_]{2,30}$",
        "description": "Acción del registro de auditoría. Se reconoce por su forma `recurso.accion`, no por una lista cerrada."
      }
    },
    "versioning_policy": {
      "compatible": [
        "add_optional_field",
        "add_endpoint",
        "add_event_type",
        "add_error_code",
        "add_open_enum_value",
        "add_optional_parameter"
      ],
      "breaking": [
        "remove_or_rename_field",
        "change_field_type",
        "add_required_request_field",
        "add_value_to_closed_enum",
        "remove_enum_value",
        "close_open_enum",
        "change_state_meaning",
        "change_mcp_tool_text"
      ],
      "communication": [
        "changelog_entry",
        "new_dated_version",
        "pinned_keys_unaffected",
        "deprecation_notice"
      ]
    },
    "rate_limits": {
      "status": "PROPUESTA justificada, no medida; se mide en el hito A3.",
      "headers": [
        "RateLimit-Limit",
        "RateLimit-Remaining",
        "RateLimit-Reset",
        "Retry-After"
      ],
      "policies": [
        {
          "id": "requests_per_key",
          "applies": "Toda petición autenticada (lecturas incluidas)",
          "scope": "key",
          "windowSeconds": 60,
          "test": 120,
          "live": 60,
          "burst": 30,
          "justification": "2 por segundo sostenido cubre sondeos de `GET /v1/spends/{id}` cada 5 s más un par de agentes por llave. 24 propuso 60/min (supuesto); se duplica en prueba para no frenar a quien depura. En real arranca en la mitad y sube con revision (autonomia gradual, 24 3 #13)."
        },
        {
          "id": "spend_creation_per_agent",
          "applies": "POST /v1/spends",
          "scope": "agent",
          "windowSeconds": 60,
          "test": 20,
          "live": 10,
          "burst": 5,
          "justification": "El límite que importa no es de rendimiento sino de seguridad: un agente en bucle (22 4.8). 20/min es más de lo que un modelo razonable pide; 10/min en real coincide con 24 (supuesto). Un agente de micropagos legitimo lo sube con revision."
        },
        {
          "id": "spend_creation_per_agent_daily",
          "applies": "POST /v1/spends",
          "scope": "agent",
          "windowSeconds": 86400,
          "test": 1000,
          "live": 200,
          "burst": 0,
          "justification": "1.000/día por agente en prueba (24 5.3); en real 200 al inicio, subible."
        },
        {
          "id": "spend_check_per_agent",
          "applies": "POST /v1/spends/check",
          "scope": "agent",
          "windowSeconds": 60,
          "test": 60,
          "live": 30,
          "burst": 10,
          "justification": "Es barata pero revela límites a un agente comprometido; ritmo medio entre lectura y pago."
        },
        {
          "id": "owner_admin_writes_per_key",
          "applies": "Escrituras de la API de administración (agentes, reglas, destinos, llaves)",
          "scope": "key",
          "windowSeconds": 60,
          "test": 30,
          "live": 15,
          "burst": 10,
          "justification": "Son acciones humanas o de un script de despliegue; 30/min sobra y limita el dano de una llave de dueño robada."
        },
        {
          "id": "key_rotations_per_owner_daily",
          "applies": "POST /v1/keys/{id}/rotate y creacion de llaves",
          "scope": "owner",
          "windowSeconds": 86400,
          "test": 50,
          "live": 10,
          "burst": 0,
          "justification": "Rotar es raro; un tope diario evita llenar el límite de 3 llaves activas por agente con basura."
        },
        {
          "id": "sandbox_control_per_owner",
          "applies": "/v1/test/* (reloj, reinicio, fondeo, reentrega)",
          "scope": "owner",
          "windowSeconds": 3600,
          "test": 120,
          "live": 0,
          "burst": 20,
          "justification": "Solo existe con llaves de prueba (con llave real responde 404). Las pruebas automaticas avanzan el reloj muchas veces."
        },
        {
          "id": "failed_auth_per_ip",
          "applies": "Peticiones con llave inválida o ausente (401)",
          "scope": "ip",
          "windowSeconds": 600,
          "test": 30,
          "live": 30,
          "burst": 0,
          "justification": "Frena la adivinanza de llaves y el sondeo. Con el CRC de la llave la mayoria de intentos falla sin tocar la base."
        }
      ]
    },
    "quotas": {
      "maxActiveAgentsTest": 5,
      "maxActiveAgentsLive": 10,
      "maxArchivedAgents": 20,
      "maxActiveKeysPerAgent": 3,
      "maxActiveOwnerKeys": 3,
      "maxSpendsPerOwnerTest": 5000,
      "maxWebhookEndpointsPerOwner": 10,
      "testBalanceCap": "10000.00",
      "testFundingsPerDay": 5,
      "eventRetentionDays": 30
    },
    "limits": {
      "maxRequestBodyBytes": 16384,
      "maxMemoLength": 280,
      "maxClientReferenceLength": 64,
      "maxDestinationLength": 253,
      "maxResourceUrlLength": 2048,
      "maxResourceBodyLength": 8192,
      "maxAgentNameLength": 60,
      "listDefaultLimit": 10,
      "listMaxLimit": 50,
      "maxWaitSeconds": 20,
      "approvalDefaultTtlMinutes": 15,
      "approvalMinTtlMinutes": 5,
      "approvalMaxTtlMinutes": 60,
      "idempotencyMemoryHours": 24,
      "duplicateGuardSeconds": 60,
      "uncertainProcessingAlertHours": 24,
      "maxSettlementBodyChars": 20000,
      "memoPreviewInLists": 80,
      "keyDefaultExpiryDaysTest": 90,
      "keyDefaultExpiryDaysLive": 30,
      "keyRotationGraceDaysMax": 7,
      "paymentSignatureTtlSeconds": 60,
      "looseningDelayMinutesTest": 10,
      "looseningDelayHoursLive": 24
    },
    "idempotency": {
      "header": "Idempotency-Key",
      "scope": "por agente y por entorno (prueba/real). Las acciones del dueño usan (dueño, entorno, llave).",
      "guarantee": "Con la misma llave y la misma huella devuelve el estado ACTUAL del mismo pago con `idempotent_replay: true`, sin pagar de nuevo (no el JSON viejo).",
      "fingerprintIncludes": [
        "amount normalizado",
        "currency",
        "destination normalizado",
        "resource {method, host, path normalizados}"
      ],
      "fingerprintExcludes": [
        "memo",
        "client_reference"
      ],
      "fingerprintWhy": "Un modelo reescribe el memo cada vez que reintenta; incluirlo produciria falsos 409 (27 B M9).",
      "otherFingerprint": "409 `idempotency_conflict` con `changed_fields` que nombra lo que cambio.",
      "inFlight": "409 `idempotency_key_in_use` (reintentable, con `Retry-After`) si otra petición con la llave sigue en curso.",
      "failed": "Un pago `failed` deja la llave GASTADA: repetirla devuelve el mismo `failed`. Un intento nuevo exige una llave nueva (M8).",
      "duplicateGuard": "Misma compra (agente, monto, destino, recurso) con OTRA llave en 60 s => `pending_approval` con `approval_reason: possible_duplicate`, salvo que el anterior fuera `failed`.",
      "failClosed": "Si la tabla de idempotencia no se puede leer, NO se paga (falla cerrado; x402 falla abierto y no lo copiamos).",
      "retention": "Se garantiza memoria de 24 h como mínimo. HUECO ABIERTO: la base tiene UNIQUE (agente, entorno, llave) sin caducidad (004:58) y 27 E.3 #46 pide que pasadas 24 h sea un pago nuevo. El contrato prohibe reutilizar una llave para otro pago; el comportamiento posterior a 24 h no se promete."
    },
    "webhook_delivery": {
      "status": "PROPUESTA para B2.",
      "headers": {
        "signature": "Nouron-Signature",
        "eventId": "Nouron-Event-Id",
        "eventType": "Nouron-Event",
        "delivery": "Nouron-Delivery",
        "userAgent": "NouronPass-Webhooks/1.0"
      },
      "signature": {
        "algorithm": "HMAC-SHA256",
        "headerFormat": "t=<segundos>,v1=<hex>",
        "toleranceSeconds": 300,
        "secretPrefix": "whsec_",
        "rotationGraceHours": 24
      },
      "retry_wait_minutes": [
        0,
        1,
        5,
        30,
        120,
        240,
        480,
        564
      ],
      "timeoutSeconds": 5,
      "maxAttempts": 8,
      "consecutiveFailuresToPause": 20,
      "maxEndpointsPerOwner": 10,
      "eventRetentionDays": 30,
      "httpsPort": 443
    }
  }
}
