{
  "openapi": "3.1.0",
  "info": {
    "title": "AgentUtils API v2",
    "version": "2.0.0",
    "description": "Multi-tenant, agent-native infrastructure: KV store, audit log, dead-letter queue, scheduler, human-in-the-loop checkpoints, and image upload. Tenant-isolated, callback-signed, idempotent.\n\n## Base URL\nhttps://www.agent-utils.com/v1\n\n## Authentication\nServer-derived identity from key prefix:\n- `agutil_adm_\u2026` \u2014 admin key (tenant scope). Header: `x-admin-key`.\n- `agutil_agt_\u2026` \u2014 agent key (tenant + agent scope). Headers: `x-agent-id` + `x-api-key`.\n- `agutil_apr_\u2026` \u2014 approval-proxy key (HitL approve/reject only). Header: `X-Approval-Key`.\n\n`tenant_id` is always server-derived \u2014 never accepted from the client.\n\n## Standard headers\n- `Idempotency-Key` \u2014 replay-safe on all `POST` creation endpoints.\n- All responses include `X-Request-Id`.\n\n## Error envelope\n`{ \"error\": { \"code\", \"message\", \"details\", \"request_id\" } }`"
  },
  "servers": [
    {
      "url": "https://www.agent-utils.com/v1"
    }
  ],
  "tags": [
    {
      "name": "Tenants",
      "description": "Tenant lifecycle, quota, admin-key rotation"
    },
    {
      "name": "Agents",
      "description": "Agent registration and key rotation"
    },
    {
      "name": "Approval Keys",
      "description": "Approval-proxy keys for delegated HitL"
    },
    {
      "name": "KV Store",
      "description": "Tenant-isolated KV with CAS, TTL, namespaces"
    },
    {
      "name": "Audit Log",
      "description": "Append-only, server-timestamped audit trail"
    },
    {
      "name": "Dead Letter Queue",
      "description": "Independent pull-based failure inbox"
    },
    {
      "name": "Scheduler",
      "description": "Once-callbacks with fixed retry + DLQ cascade"
    },
    {
      "name": "Human-in-the-Loop",
      "description": "Checkpoints requiring human approval"
    },
    {
      "name": "Confessions",
      "description": "Cloud-agent uncertainty reports and human steering"
    },
    {
      "name": "Image Upload",
      "description": "Hosted image URLs from a single upload"
    },
    {
      "name": "Connections",
      "description": "One-time pairing and connection status"
    },
    {
      "name": "Secure Handoffs",
      "description": "Encrypted credential handoffs between agents and owners"
    },
    {
      "name": "System",
      "description": "Cron tick (internal)"
    }
  ],
  "components": {
    "securitySchemes": {
      "adminKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-admin-key",
        "description": "Admin key `agutil_adm_\u2026`"
      },
      "agentKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Agent key `agutil_agt_\u2026` (with `x-agent-id`)"
      },
      "approvalKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Approval-Key",
        "description": "Approval-proxy key `agutil_apr_\u2026`"
      },
      "connectionCredential": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "au_conn_\u2026",
        "description": "Connection credential returned once when a pairing code is redeemed"
      },
      "cronSecret": {
        "type": "http",
        "scheme": "bearer",
        "description": "CRON_SECRET bearer for the cron tick"
      }
    },
    "parameters": {
      "tenantId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "agentId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "dlqId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "checkpointId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "confessionId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object"
              },
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      },
      "TenantCreate": {
        "type": "object",
        "required": [
          "name",
          "owner_email"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 3,
            "maxLength": 40
          },
          "owner_email": {
            "type": "string",
            "format": "email"
          },
          "plan": {
            "type": "string",
            "enum": [
              "free",
              "pro"
            ],
            "default": "free"
          }
        }
      },
      "TenantCreated": {
        "type": "object",
        "properties": {
          "tenant_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          },
          "admin_key": {
            "type": "string",
            "description": "One-time \u2014 shown only here"
          },
          "quota": {
            "type": "object"
          }
        }
      },
      "AgentCreate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "pattern": "^[a-z0-9][a-z0-9-]{2,31}$"
          },
          "description": {
            "type": "string"
          },
          "callback_base_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "KvPut": {
        "type": "object",
        "required": [
          "value"
        ],
        "properties": {
          "value": {},
          "ttl_seconds": {
            "type": "integer",
            "minimum": 1
          },
          "cas_version": {
            "type": "integer",
            "description": "Optimistic concurrency (If-Match)"
          }
        }
      },
      "DlqCreate": {
        "type": "object",
        "required": [
          "payload",
          "error"
        ],
        "properties": {
          "payload": {},
          "error": {
            "type": "string"
          },
          "workflow_id": {
            "type": "string"
          },
          "lock_seconds": {
            "type": "integer",
            "default": 300
          }
        }
      },
      "ScheduleCreate": {
        "type": "object",
        "required": [
          "callback_url",
          "callback_payload",
          "fire_at"
        ],
        "properties": {
          "callback_url": {
            "type": "string",
            "format": "uri"
          },
          "callback_payload": {},
          "fire_at": {
            "type": "string",
            "format": "date-time"
          },
          "dlq_on_failure": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "CheckpointCreate": {
        "type": "object",
        "required": [
          "title",
          "callback_url"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "prompt": {
            "type": "string"
          },
          "callback_url": {
            "type": "string",
            "format": "uri"
          },
          "callback_payload": {},
          "timeout_action": {
            "type": "string",
            "enum": [
              "auto_reject",
              "dlq"
            ],
            "default": "auto_reject"
          },
          "timeout_seconds": {
            "type": "integer",
            "minimum": 60
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConfessionCreate": {
        "type": "object",
        "required": [
          "title",
          "callback_url"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 256
          },
          "summary": {
            "type": "string",
            "maxLength": 4096
          },
          "context": {},
          "urgency": {
            "type": "string",
            "enum": [
              "normal",
              "high",
              "blocking"
            ],
            "default": "normal"
          },
          "reviewer_email": {
            "type": "string",
            "format": "email"
          },
          "expires_in_seconds": {
            "type": "integer",
            "minimum": 300,
            "maximum": 604800,
            "default": 86400
          },
          "callback_url": {
            "type": "string",
            "format": "uri"
          },
          "callback_payload": {}
        }
      },
      "ConfessionResolve": {
        "type": "object",
        "required": [
          "decision"
        ],
        "properties": {
          "decision": {
            "type": "string",
            "enum": [
              "approved",
              "rejected"
            ]
          },
          "by": {
            "type": "string",
            "maxLength": 128
          },
          "note": {
            "type": "string",
            "maxLength": 1024
          }
        }
      },
      "AuditAppend": {
        "type": "object",
        "required": [
          "action"
        ],
        "properties": {
          "action": {
            "type": "string"
          },
          "workflow_id": {
            "type": "string"
          },
          "actor": {
            "type": "string"
          },
          "metadata": {
            "type": "object"
          }
        }
      }
    }
  },
  "paths": {
    "/connections/pair": {
      "post": {
        "tags": [
          "Connections"
        ],
        "summary": "Pair a runtime with an agent using a one-time code",
        "description": "Public endpoint. Exchanges a single-use pairing code for a connection credential. Codes expire after 10 minutes.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "runtimeVersion": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Paired \u2014 returns the connection credential once"
          },
          "400": {
            "description": "Validation failed"
          },
          "404": {
            "description": "Invalid or expired pairing code"
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        }
      }
    },
    "/connections/status": {
      "get": {
        "tags": [
          "Connections"
        ],
        "summary": "Return status for the calling connection",
        "description": "Requires a Bearer `au_conn_\u2026` connection credential.",
        "security": [
          {
            "connectionCredential": []
          }
        ],
        "responses": {
          "200": {
            "description": "Connection, agent, plan and capabilities"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Connection revoked or inactive"
          }
        }
      }
    },
    "/handoffs": {
      "post": {
        "tags": [
          "Secure Handoffs"
        ],
        "summary": "Create an encrypted credential handoff",
        "description": "Creates a handoff owned by the calling connection and returns one-time view and submit tokens.",
        "security": [
          {
            "connectionCredential": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "fieldSchema"
                ],
                "properties": {
                  "fieldSchema": {
                    "type": "array",
                    "maxItems": 12,
                    "items": {
                      "type": "object"
                    }
                  },
                  "title": {
                    "type": "string"
                  },
                  "linkTtlHours": {
                    "type": "number"
                  },
                  "callbackUrl": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created \u2014 one-time handoff tokens"
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Authentication required"
          }
        }
      },
      "get": {
        "tags": [
          "Secure Handoffs"
        ],
        "summary": "List handoffs for the calling account",
        "security": [
          {
            "connectionCredential": []
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata-only handoff list"
          },
          "401": {
            "description": "Authentication required"
          }
        }
      }
    },
    "/handoffs/status": {
      "post": {
        "tags": [
          "Secure Handoffs"
        ],
        "summary": "Return metadata-only handoff status",
        "security": [
          {
            "connectionCredential": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "handoffId"
                ],
                "properties": {
                  "handoffId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Handoff status without secret values"
          },
          "404": {
            "description": "Not found"
          },
          "401": {
            "description": "Authentication required"
          }
        }
      }
    },
    "/handoffs/close": {
      "post": {
        "tags": [
          "Secure Handoffs"
        ],
        "summary": "Close a handoff created by the calling connection",
        "security": [
          {
            "connectionCredential": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "handoffId",
                  "reason"
                ],
                "properties": {
                  "handoffId": {
                    "type": "string"
                  },
                  "reason": {
                    "type": "string",
                    "enum": [
                      "done"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Closed and crypto-erased"
          },
          "404": {
            "description": "Not found"
          },
          "401": {
            "description": "Authentication required"
          }
        }
      }
    },
    "/handoffs/decrypt": {
      "post": {
        "tags": [
          "Secure Handoffs"
        ],
        "summary": "Decrypt values submitted to a handoff",
        "security": [
          {
            "connectionCredential": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "handoffId"
                ],
                "properties": {
                  "handoffId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plaintext values for the creating connection"
          },
          "404": {
            "description": "Not found or expired"
          },
          "401": {
            "description": "Authentication required"
          }
        }
      }
    },
    "/tenants": {
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Create tenant + admin key",
        "description": "Public. Returns a one-time admin key (`agutil_adm_\u2026`) \u2014 store it immediately.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantCreated"
                }
              }
            }
          },
          "409": {
            "description": "TENANT_NAME_TAKEN",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{id}": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Tenant quota usage",
        "security": [
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/tenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "Usage"
          },
          "403": {
            "description": "Forbidden (wrong tenant)"
          }
        }
      },
      "delete": {
        "tags": [
          "Tenants"
        ],
        "summary": "Delete tenant (hard delete)",
        "description": "Requires body `{ \"confirm\": \"DELETE ALL DATA\" }`. 30-day grace before purge.",
        "security": [
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/tenantId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "confirm"
                ],
                "properties": {
                  "confirm": {
                    "type": "string",
                    "enum": [
                      "DELETE ALL DATA"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Scheduled for deletion"
          },
          "400": {
            "description": "DELETE_REQUIRES_CONFIRM"
          }
        }
      }
    },
    "/tenants/{id}/rotate-key": {
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Rotate admin key",
        "security": [
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/tenantId"
          }
        ],
        "responses": {
          "200": {
            "description": "New one-time admin key"
          }
        }
      }
    },
    "/agents": {
      "post": {
        "tags": [
          "Agents"
        ],
        "summary": "Register agent (returns one-time agent key)",
        "security": [
          {
            "adminKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created \u2014 one-time `agutil_agt_\u2026` key"
          },
          "409": {
            "description": "AGENT_ID_TAKEN"
          },
          "402": {
            "description": "QUOTA_EXCEEDED (agents)"
          }
        }
      }
    },
    "/agents/{id}": {
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "Agent metadata (masked key)",
        "security": [
          {
            "adminKey": []
          },
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/agentId"
          }
        ],
        "responses": {
          "200": {
            "description": "Agent"
          },
          "404": {
            "description": "Not found / cross-tenant"
          }
        }
      }
    },
    "/agents/{id}/rotate-key": {
      "post": {
        "tags": [
          "Agents"
        ],
        "summary": "Rotate agent key",
        "security": [
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/agentId"
          }
        ],
        "responses": {
          "200": {
            "description": "New one-time agent key"
          }
        }
      }
    },
    "/approval-keys": {
      "post": {
        "tags": [
          "Approval Keys"
        ],
        "summary": "Create approval-proxy key",
        "description": "Returns a one-time `agutil_apr_\u2026` key usable only for checkpoint approve/reject. Scoped to a single checkpoint when `checkpoint_id` is provided.",
        "security": [
          {
            "adminKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "checkpoint_id": {
                    "type": "string"
                  },
                  "label": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created \u2014 one-time `agutil_apr_\u2026` key"
          }
        }
      }
    },
    "/kv/{namespace}/{key}": {
      "parameters": [
        {
          "name": "namespace",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Isolation boundary within the tenant"
        },
        {
          "name": "key",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "KV Store"
        ],
        "summary": "Get value (conditional on If-Match)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "412 PRECONDITION_FAILED if version differs"
          }
        ],
        "responses": {
          "200": {
            "description": "Value + X-Version header"
          },
          "404": {
            "description": "KEY_NOT_FOUND"
          },
          "412": {
            "description": "VERSION_MISMATCH"
          }
        }
      },
      "put": {
        "tags": [
          "KV Store"
        ],
        "summary": "Put value (CAS via cas_version)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KvPut"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored \u2014 returns new version"
          },
          "409": {
            "description": "VERSION_MISMATCH (CAS)"
          },
          "403": {
            "description": "NAMESPACE_FORBIDDEN"
          }
        }
      },
      "delete": {
        "tags": [
          "KV Store"
        ],
        "summary": "Delete key",
        "security": [
          {
            "agentKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "description": "KEY_NOT_FOUND"
          }
        }
      }
    },
    "/audit/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": false,
          "schema": {
            "type": "string"
          },
          "description": "Omit for list; use ?cursor= for pagination"
        }
      ],
      "post": {
        "tags": [
          "Audit Log"
        ],
        "summary": "Append audit entry (server-timestamped, immutable)",
        "security": [
          {
            "agentKey": []
          },
          {
            "adminKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuditAppend"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Appended"
          }
        }
      },
      "get": {
        "tags": [
          "Audit Log"
        ],
        "summary": "List audit entries (cursor-paginated, workflow filter)",
        "security": [
          {
            "agentKey": []
          },
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "name": "workflow_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list"
          }
        }
      }
    },
    "/dlq/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "Capture a failure",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DlqCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Captured"
          },
          "402": {
            "description": "QUOTA_EXCEEDED (dlq)"
          }
        }
      },
      "get": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "List failures (status filter, cursor)",
        "security": [
          {
            "agentKey": []
          },
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "failed",
                "claimed",
                "resolved",
                "archived"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list"
          }
        }
      },
      "delete": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "Permanently remove a DLQ item",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/dlqId"
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "404": {
            "description": "DLQ_NOT_FOUND"
          }
        }
      }
    },
    "/dlq/{id}/claim": {
      "post": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "Atomically claim a failure (lock + status=claimed)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/dlqId"
          }
        ],
        "responses": {
          "200": {
            "description": "Claimed \u2014 full payload"
          },
          "409": {
            "description": "ALREADY_CLAIMED"
          }
        }
      }
    },
    "/dlq/{id}/release": {
      "post": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "Release a claimed lock back to failed (retryable)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/dlqId"
          }
        ],
        "responses": {
          "200": {
            "description": "Released"
          }
        }
      }
    },
    "/dlq/{id}/fail": {
      "post": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "Mark claimed failure permanently failed (archived)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/dlqId"
          }
        ],
        "responses": {
          "200": {
            "description": "Failed"
          }
        }
      }
    },
    "/dlq/{id}/resolve": {
      "post": {
        "tags": [
          "Dead Letter Queue"
        ],
        "summary": "Mark failure resolved",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/dlqId"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved"
          }
        }
      }
    },
    "/schedules/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Scheduler"
        ],
        "summary": "Schedule a once-callback (fixed retry: now, +30s, +90s)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Scheduled"
          },
          "402": {
            "description": "QUOTA_EXCEEDED (active schedules)"
          }
        }
      },
      "get": {
        "tags": [
          "Scheduler"
        ],
        "summary": "List/get schedules",
        "security": [
          {
            "agentKey": []
          },
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "fired",
                "cancelled",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List/detail"
          }
        }
      },
      "patch": {
        "tags": [
          "Scheduler"
        ],
        "summary": "Update a pending schedule",
        "security": [
          {
            "agentKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      },
      "delete": {
        "tags": [
          "Scheduler"
        ],
        "summary": "Cancel a pending schedule",
        "security": [
          {
            "agentKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Cancelled"
          }
        }
      }
    },
    "/checkpoints/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Human-in-the-Loop"
        ],
        "summary": "Create checkpoint (pause for human approval)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckpointCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Checkpoint created"
          }
        }
      },
      "get": {
        "tags": [
          "Human-in-the-Loop"
        ],
        "summary": "List/poll checkpoints (?status=pending)",
        "security": [
          {
            "agentKey": []
          },
          {
            "adminKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "expired",
                "cancelled"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List/detail"
          }
        }
      },
      "delete": {
        "tags": [
          "Human-in-the-Loop"
        ],
        "summary": "Cancel a pending checkpoint (creating agent only)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Cancelled"
          }
        }
      }
    },
    "/checkpoints/{id}/approve": {
      "post": {
        "tags": [
          "Human-in-the-Loop"
        ],
        "summary": "Approve a checkpoint",
        "description": "Admin key OR approval-proxy key (`X-Approval-Key`). Fires signed callback.",
        "security": [
          {
            "adminKey": []
          },
          {
            "approvalKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/checkpointId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved"
          },
          "404": {
            "description": "Cross-tenant / not found"
          }
        }
      }
    },
    "/checkpoints/{id}/reject": {
      "post": {
        "tags": [
          "Human-in-the-Loop"
        ],
        "summary": "Reject a checkpoint",
        "description": "Admin key OR approval-proxy key. Fires signed callback. DLQ cascade if timeout_action=dlq.",
        "security": [
          {
            "adminKey": []
          },
          {
            "approvalKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/checkpointId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected"
          },
          "404": {
            "description": "Cross-tenant / not found"
          }
        }
      }
    },
    "/confessions": {
      "post": {
        "tags": [
          "Confessions"
        ],
        "summary": "Create an uncertainty report",
        "description": "Persists the Confession, returns a one-time review URL, and queues a default reviewer email asynchronously. The agent can poll or receive a signed resolution callback.",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfessionCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created \u2014 includes review_url"
          },
          "402": {
            "description": "QUOTA_EXCEEDED (confessions_pending)"
          }
        }
      },
      "get": {
        "tags": [
          "Confessions"
        ],
        "summary": "List tenant confessions",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "resolved",
                "cancelled",
                "expired"
              ]
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List"
          }
        }
      }
    },
    "/confessions/{id}": {
      "get": {
        "tags": [
          "Confessions"
        ],
        "summary": "Get/poll one confession",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/confessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Confession"
          },
          "404": {
            "description": "Cross-tenant / not found"
          }
        }
      },
      "delete": {
        "tags": [
          "Confessions"
        ],
        "summary": "Cancel a pending confession (creating agent only)",
        "security": [
          {
            "agentKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/confessionId"
          }
        ],
        "responses": {
          "204": {
            "description": "Cancelled"
          },
          "403": {
            "description": "Not the creating agent"
          },
          "409": {
            "description": "Already resolved"
          }
        }
      }
    },
    "/confessions/{id}/resolve": {
      "post": {
        "tags": [
          "Confessions"
        ],
        "summary": "Resolve a confession",
        "description": "Admin key, approval-proxy key, or a one-time reviewer token. Resolution fires a signed callback and cancels pending notification work.",
        "security": [
          {
            "adminKey": []
          },
          {
            "approvalKey": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/confessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfessionResolve"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resolved"
          },
          "409": {
            "description": "Already resolved"
          },
          "404": {
            "description": "Cross-tenant / not found"
          }
        }
      }
    },
    "/tick": {
      "post": {
        "tags": [
          "System"
        ],
        "summary": "Cron tick \u2014 fires due schedules + processes checkpoint and confession timeouts",
        "description": "Internal. Driven by external cron every 30\u201360s. See docs/product/agentutils-v2-cron.md.",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Summary of processed schedules + timeouts"
          },
          "401": {
            "description": "UNAUTHORIZED \u2014 missing/invalid CRON_SECRET"
          }
        }
      }
    },
    "/upload": {
      "post": {
        "tags": [
          "Image Upload"
        ],
        "summary": "Upload an image, get a hosted URL (auto-expires)",
        "description": "Multipart form with a `file` field (image/jpeg|png|webp|gif|avif|svg+xml, max 10 MiB) and optional numeric `retentionHours` (default 24). Returns a public `url` that serves the image with no auth; the opaque `id` is a capability token. Files past `expiresAt` return 404.",
        "security": [
          {
            "agentKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "retentionHours": {
                    "type": "number",
                    "minimum": 1,
                    "default": 24
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created \u2014 `{ data: { id, url, filename, contentType, size, expiresAt } }`"
          },
          "400": {
            "description": "Missing file / invalid retentionHours"
          },
          "413": {
            "description": "File exceeds 10 MiB"
          },
          "415": {
            "description": "Unsupported content type"
          }
        }
      }
    }
  }
}
