{
  "openapi": "3.1.0",
  "info": {
    "title": "Conav",
    "version": "0.1.0",
    "description": "Account API keys allocate bounded agent wallets. Money is integer USD cents except legacy broker fields, which are exact USD decimal strings. Lists return the latest 100 rows. 402: insufficient funds, 403: wrong scope, 409: conflicting retry or pending cleanup, 503: retryable dependency failure. Do not retry ambiguous paid operations under a new key."
  },
  "servers": [
    {
      "url": "http://localhost:8080",
      "description": "Local self-hosted installation; replace with your HTTPS Conav API URL"
    }
  ],
  "components": {
    "securitySchemes": {
      "account": {
        "type": "http",
        "scheme": "bearer",
        "description": "cnv_live_ account key; verified Supabase sessions also accepted"
      },
      "agent": {
        "type": "http",
        "scheme": "bearer",
        "description": "cnv_agent_ wallet token, sandbox-only"
      },
      "session": {
        "type": "http",
        "scheme": "bearer",
        "description": "Supabase access token; self-host operator key also accepted"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "request_id": {
            "type": "string"
          }
        }
      },
      "WalletRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "budget_cents"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "budget_cents": {
            "type": "integer",
            "minimum": 100,
            "maximum": 1000000
          },
          "expires_in_seconds": {
            "type": "integer",
            "minimum": 60,
            "maximum": 604800,
            "default": 86400
          }
        }
      },
      "Allocation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "agent_token": {
            "type": "string",
            "description": "Sensitive wallet credential. Never log it."
          },
          "env": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "CONAV_BROKER_URL",
              "CONAV_BROKER_TOKEN"
            ],
            "properties": {
              "CONAV_BROKER_URL": {
                "type": "string",
                "format": "uri"
              },
              "CONAV_BROKER_TOKEN": {
                "type": "string",
                "description": "Same scoped credential as agent_token; inject only into its sandbox."
              }
            }
          }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "available_cents": {
            "type": "integer"
          },
          "reserved_cents": {
            "type": "integer"
          },
          "spent_cents": {
            "type": "integer"
          },
          "welcome_credit_cents": {
            "type": "integer"
          }
        }
      },
      "ComputeRequest": {
        "type": "object",
        "required": [
          "provider",
          "spec"
        ],
        "additionalProperties": false,
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "modal",
              "sfcompute",
              "vastai"
            ]
          },
          "spec": {
            "type": "object",
            "description": "Provider-specific spec; GET /v1/compute/offers first. Modal: gpu,gpus,cpus,memory_gib,max_seconds. SF: chip,max_seconds. Vast: offer_id,disk_gb,max_seconds; stop destroys the rental and disk."
          }
        }
      },
      "ComputeResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Conav resource ID for subsequent requests"
          },
          "provider_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "billing_state": {
            "type": "string",
            "enum": [
              "reserved",
              "uncertain",
              "settled"
            ],
            "description": "Payment state; settled resources may still be running and need cleanup"
          },
          "billing_policy": {
            "type": "string",
            "const": "prepaid_time"
          },
          "charged_usd": {
            "type": "string",
            "description": "Cumulative prepaid charge, including confirmed extensions; early release does not refund it"
          },
          "reserved_usd": {
            "type": "string",
            "description": "Unresolved creation hold; zero after capture. Check /v1/budget for pending extension holds."
          },
          "expires_at": {
            "type": "number",
            "description": "Current deadline, Unix seconds"
          },
          "purchased_seconds": {
            "type": "integer"
          },
          "price_hourly_usd": {
            "type": "string"
          },
          "supports_extension": {
            "type": "boolean"
          }
        }
      },
      "ResourceID": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/account": {
      "get": {
        "operationId": "get_v1_account",
        "summary": "Account credit balance in USD cents",
        "security": [
          {
            "account": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/keys": {
      "get": {
        "operationId": "get_v1_keys",
        "summary": "List account key metadata, never secrets",
        "security": [
          {
            "account": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "post_v1_keys",
        "summary": "Create an account key (Verified Supabase session or self-host operator only)",
        "security": [
          {
            "session": []
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/keys/{id}": {
      "delete": {
        "operationId": "delete_v1_keys_id",
        "summary": "Revoke an account API key",
        "security": [
          {
            "session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/wallets": {
      "get": {
        "operationId": "get_v1_wallets",
        "summary": "List latest 100 owned wallets",
        "security": [
          {
            "account": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "post_v1_wallets",
        "summary": "Reserve credit and mint sandbox credentials",
        "security": [
          {
            "account": []
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Allocation"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletRequest"
              }
            }
          }
        }
      }
    },
    "/v1/wallets/{id}/close": {
      "post": {
        "operationId": "post_v1_wallets_id_close",
        "summary": "Freeze spending, clean up resources, settle, return unused credits",
        "security": [
          {
            "account": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/wallets/{id}/resources": {
      "get": {
        "operationId": "get_v1_wallets_id_resources",
        "summary": "List resources belonging to an owned wallet",
        "security": [
          {
            "account": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/billing/checkout": {
      "post": {
        "operationId": "post_v1_billing_checkout",
        "summary": "Create a Stripe Checkout session (browser session required)",
        "security": [
          {
            "session": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_cents"
                ],
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "minimum": 500,
                    "maximum": 100000
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/budget": {
      "get": {
        "operationId": "get_v1_budget",
        "summary": "Inspect wallet spending (decimal USD strings)",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compute/offers": {
      "get": {
        "operationId": "get_v1_compute_offers",
        "summary": "List approved Modal, SF Compute and Vast.ai offers",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compute/list": {
      "get": {
        "operationId": "get_v1_compute_list",
        "summary": "List wallet-owned resources",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "operationId": "get_v1_models",
        "summary": "List metered OpenRouter models",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compute/create": {
      "post": {
        "operationId": "post_v1_compute_create",
        "summary": "Prepay a fixed-duration compute lease; no early-release refund",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComputeResource"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ComputeRequest"
              }
            }
          }
        }
      }
    },
    "/v1/compute/extend": {
      "post": {
        "operationId": "post_v1_compute_extend",
        "summary": "Prepay additional seconds on an active SF or Vast lease; Modal returns extension_not_supported",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComputeResource"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id",
                  "additional_seconds"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "additional_seconds": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 86400,
                    "description": "Added to the current expiry; constrained by wallet expiry, remaining credit, and provider limits."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/run/close": {
      "post": {
        "operationId": "post_v1_run_close",
        "summary": "Freeze wallet spending and clean up agent resources",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/compute/stop": {
      "post": {
        "operationId": "post_v1_compute_stop",
        "summary": "Stop an owned resource",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceID"
              }
            }
          }
        }
      }
    },
    "/v1/compute/ssh": {
      "post": {
        "operationId": "post_v1_compute_ssh",
        "summary": "Ssh an owned resource",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceID"
              }
            }
          }
        }
      }
    },
    "/v1/compute/status": {
      "post": {
        "operationId": "post_v1_compute_status",
        "summary": "Status an owned resource",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResourceID"
              }
            }
          }
        }
      }
    },
    "/v1/compute/exec": {
      "post": {
        "operationId": "post_v1_compute_exec",
        "summary": "Execute inside an owned remote sandbox",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "command"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "command": {
                    "type": "string"
                  },
                  "timeout": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3600,
                    "default": 300
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/compute/upload": {
      "post": {
        "operationId": "post_v1_compute_upload",
        "summary": "Upload at most 8 MiB to an owned resource",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "path",
                  "content_base64"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "path": {
                    "type": "string"
                  },
                  "content_base64": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/transfer/sign": {
      "post": {
        "operationId": "post_v1_transfer_sign",
        "summary": "Sign an exact object URL when transfer storage is configured",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "object",
                  "operation"
                ],
                "properties": {
                  "object": {
                    "type": "string"
                  },
                  "operation": {
                    "type": "string",
                    "enum": [
                      "get",
                      "put"
                    ]
                  },
                  "expires_seconds": {
                    "type": "integer",
                    "default": 900
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/openrouter/key": {
      "post": {
        "operationId": "post_v1_openrouter_key",
        "summary": "Get wallet-scoped key and OpenAI-compatible base_url",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/chat/completions": {
      "post": {
        "operationId": "post_v1_chat_completions",
        "summary": "Metered non-streaming OpenRouter request",
        "security": [
          {
            "agent": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "default": {
            "description": "Structured error; preserve Idempotency-Key on retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "model",
                  "messages"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "max_tokens": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "stream": {
                    "type": "boolean",
                    "const": false
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
